summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/superseriousbusiness/activity/pub
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/codeberg.org/superseriousbusiness/activity/pub')
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/README.md270
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/activity.go49
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/actor.go128
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/base_actor.go475
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/clock.go11
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/common_behavior.go90
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/database.go152
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/delegate_actor.go249
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/doc.go9
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/federating_protocol.go125
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/federating_wrapped_callbacks.go917
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/handlers.go115
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/property_interfaces.go118
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/side_effect_actor.go1047
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/social_protocol.go83
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/social_wrapped_callbacks.go534
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/transport.go219
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/util.go1077
-rw-r--r--vendor/codeberg.org/superseriousbusiness/activity/pub/version.go15
19 files changed, 0 insertions, 5683 deletions
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/README.md b/vendor/codeberg.org/superseriousbusiness/activity/pub/README.md
deleted file mode 100644
index bb9a49b05..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/README.md
+++ /dev/null
@@ -1,270 +0,0 @@
-# pub
-
-Implements the Social and Federating Protocols in the ActivityPub specification.
-
-## Reference & Tutorial
-
-The [go-fed website](https://go-fed.org/) 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:
-
-```golang
-import (
- "codeberg.org/superseriousbusiness/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:
-
-```golang
-// 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:
-
-```golang
-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:
-
-```golang
-// 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`:
-
-```golang
-// 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.
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/activity.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/activity.go
deleted file mode 100644
index 8b3d5b486..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/activity.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package pub
-
-import (
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// Activity represents any ActivityStreams Activity type.
-//
-// The Activity types provided in the streams package implement this.
-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)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/actor.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/actor.go
deleted file mode 100644
index a9b19d1c1..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/actor.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package pub
-
-import (
- "context"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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.
-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.
- //
- // The request and data of your application will be interpreted as
- // having an HTTPS protocol scheme.
- PostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
- // PostInboxScheme is similar to PostInbox, except clients are able to
- // specify which protocol scheme to handle the incoming request and the
- // data stored within the application (HTTP, HTTPS, etc).
- PostInboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (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.
- //
- // The request will be interpreted as having an HTTPS scheme.
- PostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
- // PostOutboxScheme is similar to PostOutbox, except clients are able to
- // specify which protocol scheme to handle the incoming request and the
- // data stored within the application (HTTP, HTTPS, etc).
- PostOutboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (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)
-}
-
-// FederatingActor is an Actor that allows programmatically delivering an
-// Activity to a federating peer.
-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)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/base_actor.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/base_actor.go
deleted file mode 100644
index c509383d6..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/base_actor.go
+++ /dev/null
@@ -1,475 +0,0 @@
-package pub
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams"
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// baseActor must satisfy the Actor interface.
-var _ Actor = &baseActor{}
-
-// baseActor is an application-independent ActivityPub implementation. It does
-// not implement the entire protocol, and relies on a delegate to do so. It
-// only implements the part of the protocol that is side-effect-free, allowing
-// an existing application to write a DelegateActor that glues their application
-// into the ActivityPub world.
-//
-// It is preferred to use a DelegateActor provided by this library, so that the
-// application does not need to worry about the ActivityPub implementation.
-type baseActor struct {
- // delegate contains application-specific delegation logic.
- delegate DelegateActor
- // enableSocialProtocol enables or disables the Social API, the client to
- // server part of ActivityPub. Useful if permitting remote clients to
- // act on behalf of the users of the client application.
- enableSocialProtocol bool
- // enableFederatedProtocol enables or disables the Federated Protocol, or the
- // server to server part of ActivityPub. Useful to permit integrating
- // with the rest of the federative web.
- enableFederatedProtocol bool
- // clock simply tracks the current time.
- clock Clock
-}
-
-// baseActorFederating must satisfy the FederatingActor interface.
-var _ FederatingActor = &baseActorFederating{}
-
-// baseActorFederating is a baseActor that also satisfies the FederatingActor
-// interface.
-//
-// The baseActor is preserved as an Actor which will not successfully cast to a
-// FederatingActor.
-type baseActorFederating struct {
- baseActor
-}
-
-// 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.
-func NewSocialActor(c CommonBehavior,
- c2s SocialProtocol,
- db Database,
- clock Clock) Actor {
- return &baseActor{
- // Use SideEffectActor without s2s.
- delegate: NewSideEffectActor(c, nil, c2s, db, clock),
- enableSocialProtocol: true,
- clock: clock,
- }
-}
-
-// 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.
-func NewFederatingActor(c CommonBehavior,
- s2s FederatingProtocol,
- db Database,
- clock Clock) FederatingActor {
- return &baseActorFederating{
- baseActor{
- // Use SideEffectActor without c2s.
- delegate: NewSideEffectActor(c, s2s, nil, db, clock),
- enableFederatedProtocol: true,
- clock: clock,
- },
- }
-}
-
-// 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 NewActor(c CommonBehavior,
- c2s SocialProtocol,
- s2s FederatingProtocol,
- db Database,
- clock Clock) FederatingActor {
- return &baseActorFederating{
- baseActor{
- delegate: NewSideEffectActor(c, s2s, c2s, db, clock),
- enableSocialProtocol: true,
- enableFederatedProtocol: true,
- clock: clock,
- },
- }
-}
-
-// 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.
-//
-// If you find yourself passing a SideEffectActor in as the DelegateActor,
-// consider using NewActor, NewFederatingActor, or NewSocialActor instead.
-func NewCustomActor(delegate DelegateActor,
- enableSocialProtocol, enableFederatedProtocol bool,
- clock Clock) FederatingActor {
- return &baseActorFederating{
- baseActor{
- delegate: delegate,
- enableSocialProtocol: enableSocialProtocol,
- enableFederatedProtocol: enableFederatedProtocol,
- clock: clock,
- },
- }
-}
-
-// PostInbox implements the generic algorithm for handling a POST request to an
-// actor's inbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-//
-// Only supports serving data with identifiers having the HTTPS scheme.
-func (b *baseActor) PostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
- return b.PostInboxScheme(c, w, r, "https")
-}
-
-// PostInbox implements the generic algorithm for handling a POST request to an
-// actor's inbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-//
-// Specifying the "scheme" allows for retrieving ActivityStreams content with
-// identifiers such as HTTP, HTTPS, or other protocol schemes.
-func (b *baseActor) PostInboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) {
- // Do nothing if it is not an ActivityPub POST request.
- if !isActivityPubPost(r) {
- return false, nil
- }
- // If the Federated Protocol is not enabled, then this endpoint is not
- // enabled.
- if !b.enableFederatedProtocol {
- w.WriteHeader(http.StatusMethodNotAllowed)
- return true, nil
- }
- // Check the peer request is authentic.
- c, authenticated, err := b.delegate.AuthenticatePostInbox(c, w, r)
- if err != nil {
- return true, err
- } else if !authenticated {
- return true, nil
- }
- // Begin processing the request, but have not yet applied
- // authorization (ex: blocks). Obtain the activity reject unknown
- // activities.
- m, err := readActivityPubReq(r)
- if err != nil {
- return true, err
- }
- asValue, err := streams.ToType(c, m)
- if err != nil && !streams.IsUnmatchedErr(err) {
- return true, err
- } else if streams.IsUnmatchedErr(err) {
- // Respond with bad request -- we do not understand the type.
- w.WriteHeader(http.StatusBadRequest)
- return true, nil
- }
- activity, ok := asValue.(Activity)
- if !ok {
- return true, fmt.Errorf("activity streams value is not an Activity: %T", asValue)
- }
- if activity.GetJSONLDId() == nil {
- w.WriteHeader(http.StatusBadRequest)
- return true, nil
- }
- // Allow server implementations to set context data with a hook.
- c, err = b.delegate.PostInboxRequestBodyHook(c, r, activity)
- if err != nil {
- return true, err
- }
- // Check authorization of the activity.
- authorized, err := b.delegate.AuthorizePostInbox(c, w, activity)
- if err != nil {
- return true, err
- } else if !authorized {
- return true, nil
- }
- // Post the activity to the actor's inbox and trigger side effects for
- // that particular Activity type. It is up to the delegate to resolve
- // the given map.
- inboxId := requestId(r, scheme)
- err = b.delegate.PostInbox(c, inboxId, activity)
- if err != nil {
- // Special case: We know it is a bad request if the object or
- // target properties needed to be populated, but weren't.
- //
- // Send the rejection to the peer.
- if err == ErrObjectRequired || err == ErrTargetRequired {
- w.WriteHeader(http.StatusBadRequest)
- return true, nil
- }
- return true, err
- }
- // Our side effects are complete, now delegate determining whether to
- // do inbox forwarding, as well as the action to do it.
- if err := b.delegate.InboxForwarding(c, inboxId, activity); err != nil {
- return true, err
- }
- // Request has been processed. Begin responding to the request.
- //
- // Simply respond with an OK status to the peer.
- w.WriteHeader(http.StatusOK)
- return true, nil
-}
-
-// GetInbox implements the generic algorithm for handling a GET request to an
-// actor's inbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-func (b *baseActor) GetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
- // Do nothing if it is not an ActivityPub GET request.
- if !isActivityPubGet(r) {
- return false, nil
- }
- // Delegate authenticating and authorizing the request.
- c, authenticated, err := b.delegate.AuthenticateGetInbox(c, w, r)
- if err != nil {
- return true, err
- } else if !authenticated {
- return true, nil
- }
- // Everything is good to begin processing the request.
- oc, err := b.delegate.GetInbox(c, r)
- if err != nil {
- return true, err
- }
- // Deduplicate the 'orderedItems' property by ID.
- err = dedupeOrderedItems(oc)
- if err != nil {
- return true, err
- }
- // Request has been processed. Begin responding to the request.
- //
- // Serialize the OrderedCollection.
- m, err := streams.Serialize(oc)
- if err != nil {
- return true, err
- }
- raw, err := json.Marshal(m)
- if err != nil {
- return true, err
- }
- // Write the response.
- addResponseHeaders(w.Header(), b.clock, raw)
- w.WriteHeader(http.StatusOK)
- n, err := w.Write(raw)
- if err != nil {
- return true, err
- } else if n != len(raw) {
- return true, fmt.Errorf("ResponseWriter.Write wrote %d of %d bytes", n, len(raw))
- }
- return true, nil
-}
-
-// PostOutbox implements the generic algorithm for handling a POST request to an
-// actor's outbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-//
-// Only supports serving data with identifiers having the HTTPS scheme.
-func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
- return b.PostOutboxScheme(c, w, r, "https")
-}
-
-// PostOutbox implements the generic algorithm for handling a POST request to an
-// actor's outbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-//
-// Specifying the "scheme" allows for retrieving ActivityStreams content with
-// identifiers such as HTTP, HTTPS, or other protocol schemes.
-func (b *baseActor) PostOutboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) {
- // Do nothing if it is not an ActivityPub POST request.
- if !isActivityPubPost(r) {
- return false, nil
- }
- // If the Social API is not enabled, then this endpoint is not enabled.
- if !b.enableSocialProtocol {
- w.WriteHeader(http.StatusMethodNotAllowed)
- return true, nil
- }
- // Delegate authenticating and authorizing the request.
- c, authenticated, err := b.delegate.AuthenticatePostOutbox(c, w, r)
- if err != nil {
- return true, err
- } else if !authenticated {
- return true, nil
- }
- // Everything is good to begin processing the request.
- m, err := readActivityPubReq(r)
- if err != nil {
- return true, err
- }
- // Note that converting to a Type will NOT successfully convert types
- // not known to go-fed. This prevents accidentally wrapping an Activity
- // type unknown to go-fed in a Create below. Instead,
- // streams.ErrUnhandledType will be returned here.
- asValue, err := streams.ToType(c, m)
- if err != nil && !streams.IsUnmatchedErr(err) {
- return true, err
- } else if streams.IsUnmatchedErr(err) {
- // Respond with bad request -- we do not understand the type.
- w.WriteHeader(http.StatusBadRequest)
- return true, nil
- }
- // Allow server implementations to set context data with a hook.
- c, err = b.delegate.PostOutboxRequestBodyHook(c, r, asValue)
- if err != nil {
- return true, err
- }
- // The HTTP request steps are complete, complete the rest of the outbox
- // and delivery process.
- outboxId := requestId(r, scheme)
- activity, err := b.deliver(c, outboxId, asValue, m)
- // Special case: We know it is a bad request if the object or
- // target properties needed to be populated, but weren't.
- //
- // Send the rejection to the client.
- if err == ErrObjectRequired || err == ErrTargetRequired {
- w.WriteHeader(http.StatusBadRequest)
- return true, nil
- } else if err != nil {
- return true, err
- }
- // Respond to the request with the new Activity's IRI location.
- w.Header().Set(locationHeader, activity.GetJSONLDId().Get().String())
- w.WriteHeader(http.StatusCreated)
- return true, nil
-}
-
-// GetOutbox implements the generic algorithm for handling a Get request to an
-// actor's outbox independent on an application. It relies on a delegate to
-// implement application specific functionality.
-func (b *baseActor) GetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
- // Do nothing if it is not an ActivityPub GET request.
- if !isActivityPubGet(r) {
- return false, nil
- }
- // Delegate authenticating and authorizing the request.
- c, authenticated, err := b.delegate.AuthenticateGetOutbox(c, w, r)
- if err != nil {
- return true, err
- } else if !authenticated {
- return true, nil
- }
- // Everything is good to begin processing the request.
- oc, err := b.delegate.GetOutbox(c, r)
- if err != nil {
- return true, err
- }
- // Request has been processed. Begin responding to the request.
- //
- // Serialize the OrderedCollection.
- m, err := streams.Serialize(oc)
- if err != nil {
- return true, err
- }
- raw, err := json.Marshal(m)
- if err != nil {
- return true, err
- }
- // Write the response.
- addResponseHeaders(w.Header(), b.clock, raw)
- w.WriteHeader(http.StatusOK)
- n, err := w.Write(raw)
- if err != nil {
- return true, err
- } else if n != len(raw) {
- return true, fmt.Errorf("ResponseWriter.Write wrote %d of %d bytes", n, len(raw))
- }
- return true, nil
-}
-
-// deliver delegates all outbox handling steps and optionally will federate the
-// activity if the federated protocol is enabled.
-//
-// This function is not exported so an Actor that only supports C2S cannot be
-// type casted to a FederatingActor. It doesn't exactly fit the Send method
-// signature anyways.
-//
-// Note: 'm' is nilable.
-func (b *baseActor) deliver(c context.Context, outbox *url.URL, asValue vocab.Type, m map[string]interface{}) (activity Activity, err error) {
- // If the value is not an Activity or type extending from Activity, then
- // we need to wrap it in a Create Activity.
- if !streams.IsOrExtendsActivityStreamsActivity(asValue) {
- asValue, err = b.delegate.WrapInCreate(c, asValue, outbox)
- if err != nil {
- return
- }
- }
- // At this point, this should be a safe conversion. If this error is
- // triggered, then there is either a bug in the delegation of
- // WrapInCreate, behavior is not lining up in the generated ExtendedBy
- // code, or something else is incorrect with the type system.
- var ok bool
- activity, ok = asValue.(Activity)
- if !ok {
- err = fmt.Errorf("activity streams value is not an Activity: %T", asValue)
- return
- }
- // Delegate generating new IDs for the activity and all new objects.
- if err = b.delegate.AddNewIDs(c, activity); err != nil {
- return
- }
- // Post the activity to the actor's outbox and trigger side effects for
- // that particular Activity type.
- //
- // Since 'm' is nil-able and side effects may need access to literal nil
- // values, such as for Update activities, ensure 'm' is non-nil.
- if m == nil {
- m, err = asValue.Serialize()
- if err != nil {
- return
- }
- }
- deliverable, err := b.delegate.PostOutbox(c, activity, outbox, m)
- if err != nil {
- return
- }
- // Request has been processed and all side effects internal to this
- // application server have finished. Begin side effects affecting other
- // servers and/or the client who sent this request.
- //
- // If we are federating and the type is a deliverable one, then deliver
- // the activity to federating peers.
- if b.enableFederatedProtocol && deliverable {
- if err = b.delegate.Deliver(c, outbox, activity); err != nil {
- return
- }
- }
- return
-}
-
-// Send is programmatically accessible if the federated protocol is enabled.
-func (b *baseActorFederating) Send(c context.Context, outbox *url.URL, t vocab.Type) (Activity, error) {
- return b.deliver(c, outbox, t, nil)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/clock.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/clock.go
deleted file mode 100644
index bf19e49f7..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/clock.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package pub
-
-import (
- "time"
-)
-
-// Clock determines the time.
-type Clock interface {
- // Now returns the current time.
- Now() time.Time
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/common_behavior.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/common_behavior.go
deleted file mode 100644
index e33dce842..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/common_behavior.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package pub
-
-import (
- "context"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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 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)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/database.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/database.go
deleted file mode 100644
index 5e25455d5..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/database.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package pub
-
-import (
- "context"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-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) (unlock func(), err 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)
- // InboxesForIRI fetches inboxes corresponding to the given iri.
- // This allows your server to skip remote dereferencing of iris
- // in order to speed up message delivery, if desired.
- //
- // It is acceptable to just return nil or an empty slice for the inboxIRIs,
- // if you don't know the inbox iri, or you don't wish to use this feature.
- // In this case, the library will attempt to resolve inboxes of the iri
- // by remote dereferencing instead.
- //
- // If the input iri is the iri of an Actor, then the inbox for the actor
- // should be returned as a single-entry slice.
- //
- // If the input iri is a Collection (such as a Collection of followers),
- // then each follower inbox IRI should be returned in the inboxIRIs slice.
- //
- // The library makes this call only after acquiring a lock first.
- InboxesForIRI(c context.Context, iri *url.URL) (inboxIRIs []*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) (outbox 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) (following 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) (liked vocab.ActivityStreamsCollection, err error)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/delegate_actor.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/delegate_actor.go
deleted file mode 100644
index 0250f62ee..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/delegate_actor.go
+++ /dev/null
@@ -1,249 +0,0 @@
-package pub
-
-import (
- "context"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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 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)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/doc.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/doc.go
deleted file mode 100644
index 93c778179..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/doc.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-package pub
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_protocol.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_protocol.go
deleted file mode 100644
index 62bcf44c1..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_protocol.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package pub
-
-import (
- "context"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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 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)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_wrapped_callbacks.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_wrapped_callbacks.go
deleted file mode 100644
index 9af4f86f1..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/federating_wrapped_callbacks.go
+++ /dev/null
@@ -1,917 +0,0 @@
-package pub
-
-import (
- "context"
- "fmt"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams"
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// OnFollowBehavior enumerates the different default actions that the go-fed
-// library can provide when receiving a Follow Activity from a peer.
-type OnFollowBehavior int
-
-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
-)
-
-// 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 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
-
- // Sidechannel data -- this is set at request handling time. These must
- // be set before the callbacks are used.
-
- // db is the Database the FederatingWrappedCallbacks should use.
- db Database
- // inboxIRI is the inboxIRI that is handling this callback.
- inboxIRI *url.URL
- // addNewIds creates new 'id' entries on an activity and its objects if
- // it is a Create activity.
- addNewIds func(c context.Context, activity Activity) error
- // deliver delivers an outgoing message.
- deliver func(c context.Context, outboxIRI *url.URL, activity Activity) error
- // newTransport creates a new Transport.
- newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
-}
-
-// callbacks returns the WrappedCallbacks members into a single interface slice
-// for use in streams.Resolver callbacks.
-//
-// If the given functions have a type that collides with the default behavior,
-// 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 {
- switch fn.(type) {
- default:
- continue
- case func(context.Context, vocab.ActivityStreamsCreate) error:
- enableCreate = false
- case func(context.Context, vocab.ActivityStreamsUpdate) error:
- enableUpdate = false
- case func(context.Context, vocab.ActivityStreamsDelete) error:
- enableDelete = false
- case func(context.Context, vocab.ActivityStreamsFollow) error:
- enableFollow = false
- case func(context.Context, vocab.ActivityStreamsAccept) error:
- enableAccept = false
- case func(context.Context, vocab.ActivityStreamsReject) error:
- enableReject = false
- case func(context.Context, vocab.ActivityStreamsAdd) error:
- enableAdd = false
- case func(context.Context, vocab.ActivityStreamsRemove) error:
- enableRemove = false
- case func(context.Context, vocab.ActivityStreamsLike) error:
- enableLike = false
- case func(context.Context, vocab.ActivityStreamsAnnounce) error:
- enableAnnounce = false
- case func(context.Context, vocab.ActivityStreamsUndo) error:
- enableUndo = false
- case func(context.Context, vocab.ActivityStreamsBlock) error:
- enableBlock = false
- }
- }
- if enableCreate {
- fns = append(fns, w.create)
- }
- 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.
-func (w FederatingWrappedCallbacks) create(c context.Context, a vocab.ActivityStreamsCreate) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(iter vocab.ActivityStreamsObjectPropertyIterator) error {
- t := iter.GetType()
- if t == nil && iter.IsIRI() {
- // Attempt to dereference the IRI instead
- tport, err := w.newTransport(c, w.inboxIRI, goFedUserAgent())
- if err != nil {
- return err
- }
- resp, err := tport.Dereference(c, iter.GetIRI())
- if err != nil {
- return err
- }
- m, err := readActivityPubResp(resp)
- if err != nil {
- return err
- }
- t, err = streams.ToType(c, m)
- if err != nil {
- return err
- }
- } else if t == nil {
- return fmt.Errorf("cannot handle federated create: object is neither a value nor IRI")
- }
- id, err := GetId(t)
- if err != nil {
- return err
- }
- var unlock func()
- unlock, err = w.db.Lock(c, id)
- if err != nil {
- return err
- }
- defer unlock()
- if err := w.db.Create(c, t); err != nil {
- return err
- }
- return nil
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if err := loopFn(iter); err != nil {
- return err
- }
- }
- if w.Create != nil {
- return w.Create(c, a)
- }
- return nil
-}
-
-// update implements the federating Update activity side effects.
-func (w FederatingWrappedCallbacks) update(c context.Context, a vocab.ActivityStreamsUpdate) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- if err := mustHaveActivityOriginMatchObjects(a); err != nil {
- return err
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(iter vocab.ActivityStreamsObjectPropertyIterator) error {
- t := iter.GetType()
- if t == nil {
- return fmt.Errorf("update requires an object to be wholly provided")
- }
- id, err := GetId(t)
- if err != nil {
- return err
- }
- var unlock func()
- unlock, err = w.db.Lock(c, id)
- if err != nil {
- return err
- }
- defer unlock()
- if err := w.db.Update(c, t); err != nil {
- return err
- }
- return nil
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if err := loopFn(iter); err != nil {
- return err
- }
- }
- if w.Update != nil {
- return w.Update(c, a)
- }
- return nil
-}
-
-// deleteFn implements the federating Delete activity side effects.
-func (w FederatingWrappedCallbacks) deleteFn(c context.Context, a vocab.ActivityStreamsDelete) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- if err := mustHaveActivityOriginMatchObjects(a); err != nil {
- return err
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(iter vocab.ActivityStreamsObjectPropertyIterator) error {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- var unlock func()
- unlock, err = w.db.Lock(c, id)
- if err != nil {
- return err
- }
- defer unlock()
- if err := w.db.Delete(c, id); err != nil {
- return err
- }
- return nil
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if err := loopFn(iter); err != nil {
- return err
- }
- }
- if w.Delete != nil {
- return w.Delete(c, a)
- }
- return nil
-}
-
-// follow implements the federating Follow activity side effects.
-func (w FederatingWrappedCallbacks) follow(c context.Context, a vocab.ActivityStreamsFollow) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Check that we own at least one of the 'object' properties, and ensure
- // it is to the actor that owns this inbox.
- //
- // If not then don't send a response. It was federated to us as an FYI,
- // by mistake, or some other reason.
- unlock, err := w.db.Lock(c, w.inboxIRI)
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred.
- actorIRI, err := w.db.ActorForInbox(c, w.inboxIRI)
- unlock() // unlock even on error
- if err != nil {
- return err
- }
- // Unlock must be called by now and every branch above.
- isMe := false
- if w.OnFollow != OnFollowDoNothing {
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- if id.String() == actorIRI.String() {
- isMe = true
- break
- }
- }
- }
- if isMe {
- // Prepare the response.
- var response Activity
- if w.OnFollow == OnFollowAutomaticallyAccept {
- response = streams.NewActivityStreamsAccept()
- } else if w.OnFollow == OnFollowAutomaticallyReject {
- response = streams.NewActivityStreamsReject()
- } else {
- return fmt.Errorf("unknown OnFollowBehavior: %d", w.OnFollow)
- }
- // Set us as the 'actor'.
- me := streams.NewActivityStreamsActorProperty()
- response.SetActivityStreamsActor(me)
- me.AppendIRI(actorIRI)
- // Set the Follow as the 'object' property.
- op := streams.NewActivityStreamsObjectProperty()
- response.SetActivityStreamsObject(op)
- op.AppendActivityStreamsFollow(a)
- // Add all actors on the original Follow to the 'to' property.
- recipients := make([]*url.URL, 0)
- to := streams.NewActivityStreamsToProperty()
- response.SetActivityStreamsTo(to)
- followActors := a.GetActivityStreamsActor()
- for iter := followActors.Begin(); iter != followActors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- to.AppendIRI(id)
- recipients = append(recipients, id)
- }
- if w.OnFollow == OnFollowAutomaticallyAccept {
- // If automatically accepting, then also update our
- // followers collection with the new actors.
- //
- // If automatically rejecting, do not update the
- // followers collection.
- unlock, err := w.db.Lock(c, actorIRI)
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred.
- followers, err := w.db.Followers(c, actorIRI)
- if err != nil {
- unlock()
- return err
- }
- items := followers.GetActivityStreamsItems()
- if items == nil {
- items = streams.NewActivityStreamsItemsProperty()
- followers.SetActivityStreamsItems(items)
- }
- for _, elem := range recipients {
- items.PrependIRI(elem)
- }
- err = w.db.Update(c, followers)
- unlock() // unlock even on error
- if err != nil {
- return err
- }
- // Unlock must be called by now and every branch above.
- }
- // Lock without defer!
- unlock, err := w.db.Lock(c, w.inboxIRI)
- if err != nil {
- return err
- }
- outboxIRI, err := w.db.OutboxForInbox(c, w.inboxIRI)
- unlock() // unlock after, regardless
- if err != nil {
- return err
- }
- // Everything must be unlocked by now.
- if err := w.addNewIds(c, response); err != nil {
- return err
- } else if err := w.deliver(c, outboxIRI, response); err != nil {
- return err
- }
- }
- if w.Follow != nil {
- return w.Follow(c, a)
- }
- return nil
-}
-
-// accept implements the federating Accept activity side effects.
-func (w FederatingWrappedCallbacks) accept(c context.Context, a vocab.ActivityStreamsAccept) error {
- op := a.GetActivityStreamsObject()
- if op != nil && op.Len() > 0 {
- // Get this actor's id.
- unlock, err := w.db.Lock(c, w.inboxIRI)
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred.
- actorIRI, err := w.db.ActorForInbox(c, w.inboxIRI)
- unlock() // unlock after regardless
- if err != nil {
- return err
- }
- // Unlock must be called by now and every branch above.
- //
- // Determine if we are in a follow on the 'object' property.
- //
- // TODO: Handle Accept multiple Follow.
- var maybeMyFollowIRI *url.URL
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- t := iter.GetType()
- if t == nil && iter.IsIRI() {
- // Attempt to dereference the IRI instead
- tport, err := w.newTransport(c, w.inboxIRI, goFedUserAgent())
- if err != nil {
- return err
- }
- resp, err := tport.Dereference(c, iter.GetIRI())
- if err != nil {
- return err
- }
- m, err := readActivityPubResp(resp)
- if err != nil {
- return err
- }
- t, err = streams.ToType(c, m)
- if err != nil {
- return err
- }
- } else if t == nil {
- return fmt.Errorf("cannot handle federated create: object is neither a value nor IRI")
- }
- // Ensure it is a Follow.
- if !streams.IsOrExtendsActivityStreamsFollow(t) {
- continue
- }
- follow, ok := t.(Activity)
- if !ok {
- return fmt.Errorf("a Follow in an Accept does not satisfy the Activity interface")
- }
- followId, err := GetId(follow)
- if err != nil {
- return err
- }
- // Ensure that we are one of the actors on the Follow.
- actors := follow.GetActivityStreamsActor()
- for iter := actors.Begin(); iter != actors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- if id.String() == actorIRI.String() {
- maybeMyFollowIRI = followId
- break
- }
- }
- // Continue breaking if we found ourselves
- if maybeMyFollowIRI != nil {
- break
- }
- }
- // If we received an Accept whose 'object' is a Follow with an
- // Accept that we sent, add to the following collection.
- if maybeMyFollowIRI != nil {
- // Verify our Follow request exists and the peer didn't
- // fabricate it.
- activityActors := a.GetActivityStreamsActor()
- if activityActors == nil || activityActors.Len() == 0 {
- return fmt.Errorf("an Accept with a Follow has no actors")
- }
- // This may be a duplicate check if we dereferenced the
- // Follow above. TODO: Separate this logic to avoid
- // redundancy.
- //
- // Use an anonymous function to properly scope the
- // database lock, immediately call it.
- err = func() error {
- unlock, err := w.db.Lock(c, maybeMyFollowIRI)
- if err != nil {
- return err
- }
- defer unlock()
- t, err := w.db.Get(c, maybeMyFollowIRI)
- if err != nil {
- return err
- }
- if !streams.IsOrExtendsActivityStreamsFollow(t) {
- return fmt.Errorf("peer gave an Accept wrapping a Follow but provided a non-Follow id")
- }
- follow, ok := t.(Activity)
- if !ok {
- return fmt.Errorf("a Follow in an Accept does not satisfy the Activity interface")
- }
- // Ensure that we are one of the actors on the Follow.
- ok = false
- actors := follow.GetActivityStreamsActor()
- for iter := actors.Begin(); iter != actors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- if id.String() == actorIRI.String() {
- ok = true
- break
- }
- }
- if !ok {
- return fmt.Errorf("peer gave an Accept wrapping a Follow but we are not the actor on that Follow")
- }
- // Build map of original Accept actors
- acceptActors := make(map[string]bool)
- for iter := activityActors.Begin(); iter != activityActors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- acceptActors[id.String()] = false
- }
- // Verify all actor(s) were on the original Follow.
- followObj := follow.GetActivityStreamsObject()
- for iter := followObj.Begin(); iter != followObj.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- if _, ok := acceptActors[id.String()]; ok {
- acceptActors[id.String()] = true
- }
- }
- for _, found := range acceptActors {
- if !found {
- return fmt.Errorf("peer gave an Accept wrapping a Follow but was not an object in the original Follow")
- }
- }
- return nil
- }()
- if err != nil {
- return err
- }
- // Add the peer to our following collection.
- unlock, err := w.db.Lock(c, actorIRI)
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred.
- following, err := w.db.Following(c, actorIRI)
- if err != nil {
- unlock()
- return err
- }
- items := following.GetActivityStreamsItems()
- if items == nil {
- items = streams.NewActivityStreamsItemsProperty()
- following.SetActivityStreamsItems(items)
- }
- for iter := activityActors.Begin(); iter != activityActors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- unlock()
- return err
- }
- items.PrependIRI(id)
- }
- err = w.db.Update(c, following)
- unlock() // unlock after regardless
- if err != nil {
- return err
- }
- // Unlock must be called by now and every branch above.
- }
- }
- if w.Accept != nil {
- return w.Accept(c, a)
- }
- return nil
-}
-
-// reject implements the federating Reject activity side effects.
-func (w FederatingWrappedCallbacks) reject(c context.Context, a vocab.ActivityStreamsReject) error {
- if w.Reject != nil {
- return w.Reject(c, a)
- }
- return nil
-}
-
-// add implements the federating Add activity side effects.
-func (w FederatingWrappedCallbacks) add(c context.Context, a vocab.ActivityStreamsAdd) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- target := a.GetActivityStreamsTarget()
- if target == nil || target.Len() == 0 {
- return ErrTargetRequired
- }
- if err := add(c, op, target, w.db); err != nil {
- return err
- }
- if w.Add != nil {
- return w.Add(c, a)
- }
- return nil
-}
-
-// remove implements the federating Remove activity side effects.
-func (w FederatingWrappedCallbacks) remove(c context.Context, a vocab.ActivityStreamsRemove) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- target := a.GetActivityStreamsTarget()
- if target == nil || target.Len() == 0 {
- return ErrTargetRequired
- }
- if err := remove(c, op, target, w.db); err != nil {
- return err
- }
- if w.Remove != nil {
- return w.Remove(c, a)
- }
- return nil
-}
-
-// like implements the federating Like activity side effects.
-func (w FederatingWrappedCallbacks) like(c context.Context, a vocab.ActivityStreamsLike) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- id, err := GetId(a)
- if err != nil {
- return err
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(iter vocab.ActivityStreamsObjectPropertyIterator) error {
- objId, err := ToId(iter)
- if err != nil {
- return err
- }
- unlock, err := w.db.Lock(c, objId)
- if err != nil {
- return err
- }
- defer unlock()
- if owns, err := w.db.Owns(c, objId); err != nil {
- return err
- } else if !owns {
- return nil
- }
- t, err := w.db.Get(c, objId)
- if err != nil {
- return err
- }
- l, ok := t.(likeser)
- if !ok {
- return fmt.Errorf("cannot add Like to likes collection for type %T", t)
- }
- // Get 'likes' property on the object, creating default if
- // necessary.
- likes := l.GetActivityStreamsLikes()
- if likes == nil {
- likes = streams.NewActivityStreamsLikesProperty()
- l.SetActivityStreamsLikes(likes)
- }
- // Get 'likes' value, defaulting to a collection.
- likesT := likes.GetType()
- if likesT == nil {
- col := streams.NewActivityStreamsCollection()
- likesT = col
- likes.SetActivityStreamsCollection(col)
- }
- // Prepend the activity's 'id' on the 'likes' Collection or
- // OrderedCollection.
- if col, ok := likesT.(itemser); ok {
- items := col.GetActivityStreamsItems()
- if items == nil {
- items = streams.NewActivityStreamsItemsProperty()
- col.SetActivityStreamsItems(items)
- }
- items.PrependIRI(id)
- } else if oCol, ok := likesT.(orderedItemser); ok {
- oItems := oCol.GetActivityStreamsOrderedItems()
- if oItems == nil {
- oItems = streams.NewActivityStreamsOrderedItemsProperty()
- oCol.SetActivityStreamsOrderedItems(oItems)
- }
- oItems.PrependIRI(id)
- } else {
- return fmt.Errorf("likes type is neither a Collection nor an OrderedCollection: %T", likesT)
- }
- err = w.db.Update(c, t)
- if err != nil {
- return err
- }
- return nil
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if err := loopFn(iter); err != nil {
- return err
- }
- }
- if w.Like != nil {
- return w.Like(c, a)
- }
- return nil
-}
-
-// announce implements the federating Announce activity side effects.
-func (w FederatingWrappedCallbacks) announce(c context.Context, a vocab.ActivityStreamsAnnounce) error {
- id, err := GetId(a)
- if err != nil {
- return err
- }
- op := a.GetActivityStreamsObject()
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(iter vocab.ActivityStreamsObjectPropertyIterator) error {
- objId, err := ToId(iter)
- if err != nil {
- return err
- }
- unlock, err := w.db.Lock(c, objId)
- if err != nil {
- return err
- }
- defer unlock()
- if owns, err := w.db.Owns(c, objId); err != nil {
- return err
- } else if !owns {
- return nil
- }
- t, err := w.db.Get(c, objId)
- if err != nil {
- return err
- }
- s, ok := t.(shareser)
- if !ok {
- return fmt.Errorf("cannot add Announce to Shares collection for type %T", t)
- }
- // Get 'shares' property on the object, creating default if
- // necessary.
- shares := s.GetActivityStreamsShares()
- if shares == nil {
- shares = streams.NewActivityStreamsSharesProperty()
- s.SetActivityStreamsShares(shares)
- }
- // Get 'shares' value, defaulting to a collection.
- sharesT := shares.GetType()
- if sharesT == nil {
- col := streams.NewActivityStreamsCollection()
- sharesT = col
- shares.SetActivityStreamsCollection(col)
- }
- // Prepend the activity's 'id' on the 'shares' Collection or
- // OrderedCollection.
- if col, ok := sharesT.(itemser); ok {
- items := col.GetActivityStreamsItems()
- if items == nil {
- items = streams.NewActivityStreamsItemsProperty()
- col.SetActivityStreamsItems(items)
- }
- items.PrependIRI(id)
- } else if oCol, ok := sharesT.(orderedItemser); ok {
- oItems := oCol.GetActivityStreamsOrderedItems()
- if oItems == nil {
- oItems = streams.NewActivityStreamsOrderedItemsProperty()
- oCol.SetActivityStreamsOrderedItems(oItems)
- }
- oItems.PrependIRI(id)
- } else {
- return fmt.Errorf("shares type is neither a Collection nor an OrderedCollection: %T", sharesT)
- }
- err = w.db.Update(c, t)
- if err != nil {
- return err
- }
- return nil
- }
- if op != nil {
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if err := loopFn(iter); err != nil {
- return err
- }
- }
- }
- if w.Announce != nil {
- return w.Announce(c, a)
- }
- return nil
-}
-
-// undo implements the federating Undo activity side effects.
-func (w FederatingWrappedCallbacks) undo(c context.Context, a vocab.ActivityStreamsUndo) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- actors := a.GetActivityStreamsActor()
- if err := mustHaveActivityActorsMatchObjectActors(c, actors, op, w.newTransport, w.inboxIRI); err != nil {
- return err
- }
- if w.Undo != nil {
- return w.Undo(c, a)
- }
- return nil
-}
-
-// block implements the federating Block activity side effects.
-func (w FederatingWrappedCallbacks) block(c context.Context, a vocab.ActivityStreamsBlock) error {
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- if w.Block != nil {
- return w.Block(c, a)
- }
- return nil
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/handlers.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/handlers.go
deleted file mode 100644
index 688b8158f..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/handlers.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package pub
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
-
- "codeberg.org/superseriousbusiness/activity/streams"
-)
-
-var ErrNotFound = errors.New("go-fed/activity: ActivityStreams data not found")
-
-// 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.
-type HandlerFunc func(c context.Context, w http.ResponseWriter, r *http.Request) (isASRequest bool, err error)
-
-// 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.
-//
-// Defaults to supporting content to be retrieved by HTTPS only.
-func NewActivityStreamsHandler(db Database, clock Clock) HandlerFunc {
- return NewActivityStreamsHandlerScheme(db, clock, "https")
-}
-
-// NewActivityStreamsHandlerScheme creates a HandlerFunc to serve
-// ActivityStreams requests which are coming from other clients or servers that
-// wish to obtain an ActivityStreams representation of data provided by the
-// specified protocol scheme.
-//
-// 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.
-//
-// Specifying the "scheme" allows for retrieving ActivityStreams content with
-// identifiers such as HTTP, HTTPS, or other protocol schemes.
-//
-// Returns ErrNotFound when the database does not retrieve any data and no
-// errors occurred during retrieval.
-func NewActivityStreamsHandlerScheme(db Database, clock Clock, scheme string) HandlerFunc {
- return func(c context.Context, w http.ResponseWriter, r *http.Request) (isASRequest bool, err error) {
- // Do nothing if it is not an ActivityPub GET request
- if !isActivityPubGet(r) {
- return
- }
- isASRequest = true
- id := requestId(r, scheme)
-
- var unlock func()
-
- // Lock and obtain a copy of the requested ActivityStreams value
- unlock, err = db.Lock(c, id)
- if err != nil {
- return
- }
- // WARNING: Unlock not deferred
- t, err := db.Get(c, id)
- unlock() // unlock even on error
- if err != nil {
- return
- }
- // Unlock must have been called by this point and in every
- // branch above
- if t == nil {
- err = ErrNotFound
- return
- }
- // Remove sensitive fields.
- clearSensitiveFields(t)
- // Serialize the fetched value.
- m, err := streams.Serialize(t)
- if err != nil {
- return
- }
- raw, err := json.Marshal(m)
- if err != nil {
- return
- }
- // Construct the response.
- addResponseHeaders(w.Header(), clock, raw)
- // Write the response.
- if streams.IsOrExtendsActivityStreamsTombstone(t) {
- w.WriteHeader(http.StatusGone)
- } else {
- w.WriteHeader(http.StatusOK)
- }
- n, err := w.Write(raw)
- if err != nil {
- return
- } else if n != len(raw) {
- err = fmt.Errorf("only wrote %d of %d bytes", n, len(raw))
- return
- }
- return
- }
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/property_interfaces.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/property_interfaces.go
deleted file mode 100644
index abec7ad53..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/property_interfaces.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package pub
-
-import (
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// inReplyToer is an ActivityStreams type with an 'inReplyTo' property
-type inReplyToer interface {
- GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
-}
-
-// objecter is an ActivityStreams type with an 'object' property
-type objecter interface {
- GetActivityStreamsObject() vocab.ActivityStreamsObjectProperty
-}
-
-// targeter is an ActivityStreams type with a 'target' property
-type targeter interface {
- GetActivityStreamsTarget() vocab.ActivityStreamsTargetProperty
-}
-
-// tagger is an ActivityStreams type with a 'tag' property
-type tagger interface {
- GetActivityStreamsTag() vocab.ActivityStreamsTagProperty
-}
-
-// hrefer is an ActivityStreams type with a 'href' property
-type hrefer interface {
- GetActivityStreamsHref() vocab.ActivityStreamsHrefProperty
-}
-
-// itemser is an ActivityStreams type with an 'items' property
-type itemser interface {
- GetActivityStreamsItems() vocab.ActivityStreamsItemsProperty
- SetActivityStreamsItems(vocab.ActivityStreamsItemsProperty)
-}
-
-// orderedItemser is an ActivityStreams type with an 'orderedItems' property
-type orderedItemser interface {
- GetActivityStreamsOrderedItems() vocab.ActivityStreamsOrderedItemsProperty
- SetActivityStreamsOrderedItems(vocab.ActivityStreamsOrderedItemsProperty)
-}
-
-// publisheder is an ActivityStreams type with a 'published' property
-type publisheder interface {
- GetActivityStreamsPublished() vocab.ActivityStreamsPublishedProperty
-}
-
-// updateder is an ActivityStreams type with an 'updateder' property
-type updateder interface {
- GetActivityStreamsUpdated() vocab.ActivityStreamsUpdatedProperty
-}
-
-// toer is an ActivityStreams type with a 'to' property
-type toer interface {
- GetActivityStreamsTo() vocab.ActivityStreamsToProperty
- SetActivityStreamsTo(i vocab.ActivityStreamsToProperty)
-}
-
-// btoer is an ActivityStreams type with a 'bto' property
-type btoer interface {
- GetActivityStreamsBto() vocab.ActivityStreamsBtoProperty
- SetActivityStreamsBto(i vocab.ActivityStreamsBtoProperty)
-}
-
-// ccer is an ActivityStreams type with a 'cc' property
-type ccer interface {
- GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
- SetActivityStreamsCc(i vocab.ActivityStreamsCcProperty)
-}
-
-// bccer is an ActivityStreams type with a 'bcc' property
-type bccer interface {
- GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
- SetActivityStreamsBcc(i vocab.ActivityStreamsBccProperty)
-}
-
-// audiencer is an ActivityStreams type with an 'audience' property
-type audiencer interface {
- GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
- SetActivityStreamsAudience(i vocab.ActivityStreamsAudienceProperty)
-}
-
-// inboxer is an ActivityStreams type with an 'inbox' property
-type inboxer interface {
- GetActivityStreamsInbox() vocab.ActivityStreamsInboxProperty
-}
-
-// attributedToer is an ActivityStreams type with an 'attributedTo' property
-type attributedToer interface {
- GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
- SetActivityStreamsAttributedTo(i vocab.ActivityStreamsAttributedToProperty)
-}
-
-// likeser is an ActivityStreams type with a 'likes' property
-type likeser interface {
- GetActivityStreamsLikes() vocab.ActivityStreamsLikesProperty
- SetActivityStreamsLikes(i vocab.ActivityStreamsLikesProperty)
-}
-
-// shareser is an ActivityStreams type with a 'shares' property
-type shareser interface {
- GetActivityStreamsShares() vocab.ActivityStreamsSharesProperty
- SetActivityStreamsShares(i vocab.ActivityStreamsSharesProperty)
-}
-
-// actorer is an ActivityStreams type with an 'actor' property
-type actorer interface {
- GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
- SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
-}
-
-// appendIRIer is an ActivityStreams type that can Append IRIs.
-type appendIRIer interface {
- AppendIRI(v *url.URL)
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/side_effect_actor.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/side_effect_actor.go
deleted file mode 100644
index d98abfdb3..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/side_effect_actor.go
+++ /dev/null
@@ -1,1047 +0,0 @@
-package pub
-
-import (
- "context"
- "fmt"
- "net/http"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams"
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// sideEffectActor must satisfy the DelegateActor interface.
-var _ DelegateActor = &SideEffectActor{}
-
-// SideEffectActor is a DelegateActor that handles the ActivityPub
-// implementation side effects, but requires a more opinionated application to
-// be written.
-//
-// Note that when using the SideEffectActor with an application that good-faith
-// implements its required interfaces, the ActivityPub specification is
-// guaranteed to be correctly followed.
-type SideEffectActor struct {
- // When doing deliveries to remote servers via the s2s protocol, the side effect
- // actor will by default use the Serialize function from the streams package.
- // However, this can be overridden after the side effect actor is intantiated,
- // by setting the exposed Serialize function on the struct. For example:
- //
- // a := NewSideEffectActor(...)
- // a.Serialize = func(a vocab.Type) (m map[string]interface{}, e error) {
- // // Put your custom serializer logic here.
- // }
- //
- // Note that you should only do this *immediately* after instantiating the side
- // effect actor -- never while your application is already running, as this will
- // likely cause race conditions or other problems! In most cases, you will never
- // need to change this; it's provided solely to allow easier customization by
- // applications.
- Serialize func(a vocab.Type) (m map[string]interface{}, e error)
-
- // When doing deliveries to remote servers via the s2s protocol, it may be desirable
- // for implementations to be able to pre-sort recipients so that higher-priority
- // recipients are higher up in the delivery queue, and lower-priority recipients
- // are further down. This can be achieved by setting the DeliveryRecipientPreSort
- // function on the side effect actor after it's instantiated. For example:
- //
- // a := NewSideEffectActor(...)
- // a.DeliveryRecipientPreSort = func(actorAndCollectionIRIs []*url.URL) []*url.URL {
- // // Put your sorting logic here.
- // }
- //
- // The actorAndCollectionIRIs parameter will be the initial list of IRIs derived by
- // looking at the "to", "cc", "bto", "bcc", and "audience" properties of the activity
- // being delivered, excluding the AP public IRI, and before dereferencing of inboxes.
- // It may look something like this:
- //
- // [
- // "https://example.org/users/someone/followers", // <-- collection IRI
- // "https://another.example.org/users/someone_else", // <-- actor IRI
- // "[...]" // <-- etc
- // ]
- //
- // In this case, implementers may wish to sort the slice so that the directly-addressed
- // actor "https://another.example.org/users/someone_else" occurs at an earlier index in
- // the slice than the followers collection "https://example.org/users/someone/followers",
- // so that "@someone_else" receives the delivery first.
- //
- // Note that you should only do this *immediately* after instantiating the side
- // effect actor -- never while your application is already running, as this will
- // likely cause race conditions or other problems! It's also completely fine to not
- // set this function at all -- in this case, no pre-sorting of recipients will be
- // performed, and delivery will occur in a non-determinate order.
- DeliveryRecipientPreSort func(actorAndCollectionIRIs []*url.URL) []*url.URL
-
- common CommonBehavior
- s2s FederatingProtocol
- c2s SocialProtocol
- db Database
- clock Clock
-}
-
-// NewSideEffectActor returns a new SideEffectActor, which satisfies the
-// DelegateActor interface. Most of the time you will not need to call this
-// function, and should instead rely on the NewSocialActor, NewFederatingActor,
-// and NewActor functions, all of which use a SideEffectActor under the hood.
-// Nevertheless, this function is exposed in case application developers need
-// a SideEffectActor for some other reason (tests, monkey patches, etc).
-//
-// If you are using the returned SideEffectActor for federation, ensure that s2s
-// is not nil. Likewise, if you are using it for the social protocol, ensure
-// that c2s is not nil.
-func NewSideEffectActor(c CommonBehavior,
- s2s FederatingProtocol,
- c2s SocialProtocol,
- db Database,
- clock Clock) *SideEffectActor {
- return &SideEffectActor{
- Serialize: streams.Serialize,
- common: c,
- s2s: s2s,
- c2s: c2s,
- db: db,
- clock: clock,
- }
-}
-
-// PostInboxRequestBodyHook defers to the delegate.
-func (a *SideEffectActor) PostInboxRequestBodyHook(c context.Context, r *http.Request, activity Activity) (context.Context, error) {
- return a.s2s.PostInboxRequestBodyHook(c, r, activity)
-}
-
-// PostOutboxRequestBodyHook defers to the delegate.
-func (a *SideEffectActor) PostOutboxRequestBodyHook(c context.Context, r *http.Request, data vocab.Type) (context.Context, error) {
- return a.c2s.PostOutboxRequestBodyHook(c, r, data)
-}
-
-// AuthenticatePostInbox defers to the delegate to authenticate the request.
-func (a *SideEffectActor) AuthenticatePostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error) {
- return a.s2s.AuthenticatePostInbox(c, w, r)
-}
-
-// AuthenticateGetInbox defers to the delegate to authenticate the request.
-func (a *SideEffectActor) AuthenticateGetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error) {
- return a.common.AuthenticateGetInbox(c, w, r)
-}
-
-// AuthenticatePostOutbox defers to the delegate to authenticate the request.
-func (a *SideEffectActor) AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error) {
- return a.c2s.AuthenticatePostOutbox(c, w, r)
-}
-
-// AuthenticateGetOutbox defers to the delegate to authenticate the request.
-func (a *SideEffectActor) AuthenticateGetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error) {
- return a.common.AuthenticateGetOutbox(c, w, r)
-}
-
-// GetOutbox delegates to the SocialProtocol.
-func (a *SideEffectActor) GetOutbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
- return a.common.GetOutbox(c, r)
-}
-
-// GetInbox delegates to the FederatingProtocol.
-func (a *SideEffectActor) GetInbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
- return a.s2s.GetInbox(c, r)
-}
-
-// AuthorizePostInbox defers to the federating protocol whether the peer request
-// is authorized based on the actors' ids.
-func (a *SideEffectActor) AuthorizePostInbox(c context.Context, w http.ResponseWriter, activity Activity) (authorized bool, err error) {
- authorized = false
- actor := activity.GetActivityStreamsActor()
- if actor == nil {
- err = fmt.Errorf("no actors in post to inbox")
- return
- }
- var iris []*url.URL
- for i := 0; i < actor.Len(); i++ {
- iter := actor.At(i)
- if iter.IsIRI() {
- iris = append(iris, iter.GetIRI())
- } else if t := iter.GetType(); t != nil {
- iris = append(iris, activity.GetJSONLDId().Get())
- } else {
- err = fmt.Errorf("actor at index %d is missing an id", i)
- return
- }
- }
- // Determine if the actor(s) sending this request are blocked.
- var blocked bool
- if blocked, err = a.s2s.Blocked(c, iris); err != nil {
- return
- } else if blocked {
- w.WriteHeader(http.StatusForbidden)
- return
- }
- authorized = true
- return
-}
-
-// PostInbox handles the side effects of determining whether to block the peer's
-// request, adding the activity to the actor's inbox, and triggering side
-// effects based on the activity's type.
-func (a *SideEffectActor) PostInbox(c context.Context, inboxIRI *url.URL, activity Activity) error {
- isNew, err := a.addToInboxIfNew(c, inboxIRI, activity)
- if err != nil {
- return err
- }
- if isNew {
- wrapped, other, err := a.s2s.FederatingCallbacks(c)
- if err != nil {
- return err
- }
- // Populate side channels.
- wrapped.db = a.db
- wrapped.inboxIRI = inboxIRI
- wrapped.newTransport = a.common.NewTransport
- wrapped.deliver = a.Deliver
- wrapped.addNewIds = a.AddNewIDs
- res, err := streams.NewTypeResolver(wrapped.callbacks(other)...)
- if err != nil {
- return err
- }
- if err = res.Resolve(c, activity); err != nil && !streams.IsUnmatchedErr(err) {
- return err
- } else if streams.IsUnmatchedErr(err) {
- err = a.s2s.DefaultCallback(c, activity)
- if err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// InboxForwarding implements the 3-part inbox forwarding algorithm specified in
-// the ActivityPub specification. Does not modify the Activity, but may send
-// outbound requests as a side effect.
-//
-// InboxForwarding sets the federated data in the database.
-func (a *SideEffectActor) InboxForwarding(c context.Context, inboxIRI *url.URL, activity Activity) error {
- // 1. Must be first time we have seen this Activity.
- //
- // Obtain the id of the activity
- id := activity.GetJSONLDId()
- // Acquire a lock for the id. To be held for the rest of execution.
- unlock, err := a.db.Lock(c, id.Get())
- if err != nil {
- return err
- }
- // WARNING: Unlock is not deferred
- //
- // If the database already contains the activity, exit early.
- exists, err := a.db.Exists(c, id.Get())
- if err != nil {
- unlock()
- return err
- } else if exists {
- unlock()
- return nil
- }
- // Attempt to create the activity entry.
- err = a.db.Create(c, activity)
- unlock() // unlock even on error return
- if err != nil {
- return err
- }
- // Unlock by this point and in every branch above.
- //
- // 2. The values of 'to', 'cc', or 'audience' are Collections owned by
- // this server.
- var r []*url.URL
- to := activity.GetActivityStreamsTo()
- if to != nil {
- for iter := to.Begin(); iter != to.End(); iter = iter.Next() {
- val, err := ToId(iter)
- if err != nil {
- return err
- }
- r = append(r, val)
- }
- }
- cc := activity.GetActivityStreamsCc()
- if cc != nil {
- for iter := cc.Begin(); iter != cc.End(); iter = iter.Next() {
- val, err := ToId(iter)
- if err != nil {
- return err
- }
- r = append(r, val)
- }
- }
- audience := activity.GetActivityStreamsAudience()
- if audience != nil {
- for iter := audience.Begin(); iter != audience.End(); iter = iter.Next() {
- val, err := ToId(iter)
- if err != nil {
- return err
- }
- r = append(r, val)
- }
- }
- // Find all IRIs owned by this server. We need to find all of them so
- // that forwarding can properly occur.
- var myIRIs []*url.URL
- for _, iri := range r {
- if err != nil {
- return err
- }
- var unlock func()
- unlock, err = a.db.Lock(c, iri)
- if err != nil {
- return err
- }
- // WARNING: Unlock is not deferred
- owns, err := a.db.Owns(c, iri)
- unlock() // unlock even on error
- if err != nil {
- return err
- } else if !owns {
- continue
- }
- // Unlock by this point and in every branch above.
- myIRIs = append(myIRIs, iri)
- }
- // Finally, load our IRIs to determine if they are a Collection or
- // OrderedCollection.
- //
- // Load the unfiltered IRIs.
- var colIRIs []*url.URL
- col := make(map[string]itemser)
- oCol := make(map[string]orderedItemser)
- for _, iri := range myIRIs {
- var unlock func()
- unlock, err = a.db.Lock(c, iri)
- if err != nil {
- return err
- }
- // WARNING: Not Unlocked
- t, err := a.db.Get(c, iri)
- if err != nil {
- return err
- }
- if streams.IsOrExtendsActivityStreamsOrderedCollection(t) {
- if im, ok := t.(orderedItemser); ok {
- oCol[iri.String()] = im
- colIRIs = append(colIRIs, iri)
- defer unlock()
- } else {
- unlock() // unlock instantly
- }
- } else if streams.IsOrExtendsActivityStreamsCollection(t) {
- if im, ok := t.(itemser); ok {
- col[iri.String()] = im
- colIRIs = append(colIRIs, iri)
- defer unlock()
- } else {
- unlock() // unlock instantly
- }
- } else {
- unlock() // unlock instantly
- }
- }
- // If we own none of the Collection IRIs in 'to', 'cc', or 'audience'
- // then no need to do inbox forwarding. We have nothing to forward to.
- if len(colIRIs) == 0 {
- return nil
- }
- // 3. The values of 'inReplyTo', 'object', 'target', or 'tag' are owned
- // by this server. This is only a boolean trigger: As soon as we get
- // a hit that we own something, then we should do inbox forwarding.
- maxDepth := a.s2s.MaxInboxForwardingRecursionDepth(c)
- ownsValue, err := a.hasInboxForwardingValues(c, inboxIRI, activity, maxDepth, 0)
- if err != nil {
- return err
- }
- // If we don't own any of the 'inReplyTo', 'object', 'target', or 'tag'
- // values, then no need to do inbox forwarding.
- if !ownsValue {
- return nil
- }
- // Do the inbox forwarding since the above conditions hold true. Support
- // the behavior of letting the application filter out the resulting
- // collections to be targeted.
- toSend, err := a.s2s.FilterForwarding(c, colIRIs, activity)
- if err != nil {
- return err
- }
- recipients := make([]*url.URL, 0, len(toSend))
- for _, iri := range toSend {
- if c, ok := col[iri.String()]; ok {
- if it := c.GetActivityStreamsItems(); it != nil {
- for iter := it.Begin(); iter != it.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- recipients = append(recipients, id)
- }
- }
- } else if oc, ok := oCol[iri.String()]; ok {
- if oit := oc.GetActivityStreamsOrderedItems(); oit != nil {
- for iter := oit.Begin(); iter != oit.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- recipients = append(recipients, id)
- }
- }
- }
- }
- return a.deliverToRecipients(c, inboxIRI, activity, recipients)
-}
-
-// PostOutbox handles the side effects of adding the activity to the actor's
-// outbox, and triggering side effects based on the activity's type.
-//
-// This implementation assumes all types are meant to be delivered except for
-// the ActivityStreams Block type.
-func (a *SideEffectActor) PostOutbox(c context.Context, activity Activity, outboxIRI *url.URL, rawJSON map[string]interface{}) (deliverable bool, err error) {
- // TODO: Determine this if c2s is nil
- deliverable = true
- if a.c2s != nil {
- var wrapped SocialWrappedCallbacks
- var other []interface{}
- wrapped, other, err = a.c2s.SocialCallbacks(c)
- if err != nil {
- return
- }
- // Populate side channels.
- wrapped.db = a.db
- wrapped.outboxIRI = outboxIRI
- wrapped.rawActivity = rawJSON
- wrapped.clock = a.clock
- wrapped.newTransport = a.common.NewTransport
- undeliverable := false
- wrapped.undeliverable = &undeliverable
- var res *streams.TypeResolver
- res, err = streams.NewTypeResolver(wrapped.callbacks(other)...)
- if err != nil {
- return
- }
- if err = res.Resolve(c, activity); err != nil && !streams.IsUnmatchedErr(err) {
- return
- } else if streams.IsUnmatchedErr(err) {
- deliverable = true
- err = a.c2s.DefaultCallback(c, activity)
- if err != nil {
- return
- }
- } else {
- deliverable = !undeliverable
- }
- }
- err = a.addToOutbox(c, outboxIRI, activity)
- return
-}
-
-// AddNewIDs creates new 'id' entries on an activity and its objects if it is a
-// Create activity.
-func (a *SideEffectActor) AddNewIDs(c context.Context, activity Activity) error {
- id, err := a.db.NewID(c, activity)
- if err != nil {
- return err
- }
- activityId := streams.NewJSONLDIdProperty()
- activityId.Set(id)
- activity.SetJSONLDId(activityId)
- if streams.IsOrExtendsActivityStreamsCreate(activity) {
- o, ok := activity.(objecter)
- if !ok {
- return fmt.Errorf("cannot add new id for Create: %T has no object property", activity)
- }
- if oProp := o.GetActivityStreamsObject(); oProp != nil {
- for iter := oProp.Begin(); iter != oProp.End(); iter = iter.Next() {
- t := iter.GetType()
- if t == nil {
- return fmt.Errorf("cannot add new id for object in Create: object is not embedded as a value literal")
- }
- id, err = a.db.NewID(c, t)
- if err != nil {
- return err
- }
- objId := streams.NewJSONLDIdProperty()
- objId.Set(id)
- t.SetJSONLDId(objId)
- }
- }
- }
- return nil
-}
-
-// deliver will complete the peer-to-peer sending of a federated message to
-// another server.
-//
-// Must be called if at least the federated protocol is supported.
-func (a *SideEffectActor) Deliver(c context.Context, outboxIRI *url.URL, activity Activity) error {
- recipients, err := a.prepare(c, outboxIRI, activity)
- if err != nil {
- return err
- }
- return a.deliverToRecipients(c, outboxIRI, activity, recipients)
-}
-
-// WrapInCreate wraps an object with a Create activity.
-func (a *SideEffectActor) WrapInCreate(c context.Context, obj vocab.Type, outboxIRI *url.URL) (create vocab.ActivityStreamsCreate, err error) {
- var unlock func()
- unlock, err = a.db.Lock(c, outboxIRI)
- if err != nil {
- return
- }
- // WARNING: No deferring the Unlock
- actorIRI, err := a.db.ActorForOutbox(c, outboxIRI)
- unlock() // unlock after regardless
- if err != nil {
- return
- }
- // Unlock the lock at this point and every branch above
- return wrapInCreate(c, obj, actorIRI)
-}
-
-// deliverToRecipients will take a prepared Activity and send it to specific
-// recipients on behalf of an actor.
-func (a *SideEffectActor) deliverToRecipients(c context.Context, boxIRI *url.URL, activity Activity, recipients []*url.URL) error {
- // Call whichever serializer is
- // set on the side effect actor.
- m, err := a.Serialize(activity)
- if err != nil {
- return err
- }
-
- tp, err := a.common.NewTransport(c, boxIRI, goFedUserAgent())
- if err != nil {
- return err
- }
-
- return tp.BatchDeliver(c, m, recipients)
-}
-
-// addToOutbox adds the activity to the outbox and creates the activity in the
-// internal database as its own entry.
-func (a *SideEffectActor) addToOutbox(c context.Context, outboxIRI *url.URL, activity Activity) error {
- // Set the activity in the database first.
- id := activity.GetJSONLDId()
- unlock, err := a.db.Lock(c, id.Get())
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred
- err = a.db.Create(c, activity)
- unlock() // unlock after regardless
- if err != nil {
- return err
- }
- // WARNING: Unlock(c, id) should be called by this point and in every
- // return before here.
- //
- // Acquire a lock to read the outbox. Defer release.
- unlock, err = a.db.Lock(c, outboxIRI)
- if err != nil {
- return err
- }
- defer unlock()
- outbox, err := a.db.GetOutbox(c, outboxIRI)
- if err != nil {
- return err
- }
- // Prepend the activity to the list of 'orderedItems'.
- oi := outbox.GetActivityStreamsOrderedItems()
- if oi == nil {
- oi = streams.NewActivityStreamsOrderedItemsProperty()
- }
- oi.PrependIRI(id.Get())
- outbox.SetActivityStreamsOrderedItems(oi)
- // Save in the database.
- err = a.db.SetOutbox(c, outbox)
- return err
-}
-
-// addToInboxIfNew will add the activity to the inbox at the specified IRI if
-// the activity's ID has not yet been added to the inbox.
-//
-// It does not add the activity to this database's know federated data.
-//
-// Returns true when the activity is novel.
-func (a *SideEffectActor) addToInboxIfNew(c context.Context, inboxIRI *url.URL, activity Activity) (isNew bool, err error) {
- // Acquire a lock to read the inbox. Defer release.
- var unlock func()
- unlock, err = a.db.Lock(c, inboxIRI)
- if err != nil {
- return
- }
- defer unlock()
- // Obtain the id of the activity
- id := activity.GetJSONLDId()
- // If the inbox already contains the URL, early exit.
- contains, err := a.db.InboxContains(c, inboxIRI, id.Get())
- if err != nil {
- return
- } else if contains {
- return
- }
- // It is a new id, acquire the inbox.
- isNew = true
- inbox, err := a.db.GetInbox(c, inboxIRI)
- if err != nil {
- return
- }
- // Prepend the activity to the list of 'orderedItems'.
- oi := inbox.GetActivityStreamsOrderedItems()
- if oi == nil {
- oi = streams.NewActivityStreamsOrderedItemsProperty()
- }
- oi.PrependIRI(id.Get())
- inbox.SetActivityStreamsOrderedItems(oi)
- // Save in the database.
- err = a.db.SetInbox(c, inbox)
- return
-}
-
-// Given an ActivityStreams value, recursively examines ownership of the id or
-// href and the ones on properties applicable to inbox forwarding.
-//
-// Recursion may be limited by providing a 'maxDepth' greater than zero. A
-// value of zero or a negative number will result in infinite recursion.
-func (a *SideEffectActor) hasInboxForwardingValues(c context.Context, inboxIRI *url.URL, val vocab.Type, maxDepth, currDepth int) (bool, error) {
- // Stop recurring if we are exceeding the maximum depth and the maximum
- // is a positive number.
- if maxDepth > 0 && currDepth >= maxDepth {
- return false, nil
- }
- // Determine if we own the 'id' of any values on the properties we care
- // about.
- types, iris := getInboxForwardingValues(val)
- // For IRIs, simply check if we own them.
- for _, iri := range iris {
- unlock, err := a.db.Lock(c, iri)
- if err != nil {
- return false, err
- }
- // WARNING: Unlock is not deferred
- owns, err := a.db.Owns(c, iri)
- unlock() // unlock after regardless
- if err != nil {
- return false, err
- } else if owns {
- return true, nil
- }
- // Unlock by this point and in every branch above
- }
- // For embedded literals, check the id.
- for _, val := range types {
- id, err := GetId(val)
- if err != nil {
- return false, err
- }
- var unlock func()
- unlock, err = a.db.Lock(c, id)
- if err != nil {
- return false, err
- }
- // WARNING: Unlock is not deferred
- owns, err := a.db.Owns(c, id)
- unlock() // unlock after regardless
- if err != nil {
- return false, err
- } else if owns {
- return true, nil
- }
- // Unlock by this point and in every branch above
- }
- // Recur Preparation: Try fetching the IRIs so we can recur into them.
- for _, iri := range iris {
- // Dereferencing the IRI.
- tport, err := a.common.NewTransport(c, inboxIRI, goFedUserAgent())
- if err != nil {
- return false, err
- }
- resp, err := tport.Dereference(c, iri)
- if err != nil {
- // Do not fail the entire process if the data is
- // missing.
- continue
- }
- m, err := readActivityPubResp(resp)
- if err != nil {
- return false, err
- }
- t, err := streams.ToType(c, m)
- if err != nil {
- // Do not fail the entire process if we cannot handle
- // the type.
- continue
- }
- types = append(types, t)
- }
- // Recur.
- for _, nextVal := range types {
- if has, err := a.hasInboxForwardingValues(c, inboxIRI, nextVal, maxDepth, currDepth+1); err != nil {
- return false, err
- } else if has {
- return true, nil
- }
- }
- return false, nil
-}
-
-// prepare takes a deliverableObject and returns a list of the final
-// recipient inbox IRIs. Additionally, the deliverableObject will have
-// any hidden hidden recipients ("bto" and "bcc") stripped from it.
-//
-// Only call if both the social and federated protocol are supported.
-func (a *SideEffectActor) prepare(
- ctx context.Context,
- outboxIRI *url.URL,
- activity Activity,
-) ([]*url.URL, error) {
- // Iterate through to, bto, cc, bcc, and audience
- // to extract a slice of addressee IRIs / IDs.
- //
- // The resulting slice might look something like:
- //
- // [
- // "https://example.org/users/someone/followers", // <-- collection IRI
- // "https://another.example.org/users/someone_else", // <-- actor IRI
- // "[...]" // <-- etc
- // ]
- var actorsAndCollections []*url.URL
- if to := activity.GetActivityStreamsTo(); to != nil {
- for iter := to.Begin(); iter != to.End(); iter = iter.Next() {
- var err error
- actorsAndCollections, err = appendToActorsAndCollectionsIRIs(
- iter, actorsAndCollections,
- )
- if err != nil {
- return nil, err
- }
- }
- }
-
- if bto := activity.GetActivityStreamsBto(); bto != nil {
- for iter := bto.Begin(); iter != bto.End(); iter = iter.Next() {
- var err error
- actorsAndCollections, err = appendToActorsAndCollectionsIRIs(
- iter, actorsAndCollections,
- )
- if err != nil {
- return nil, err
- }
- }
- }
-
- if cc := activity.GetActivityStreamsCc(); cc != nil {
- for iter := cc.Begin(); iter != cc.End(); iter = iter.Next() {
- var err error
- actorsAndCollections, err = appendToActorsAndCollectionsIRIs(
- iter, actorsAndCollections,
- )
- if err != nil {
- return nil, err
- }
- }
- }
-
- if bcc := activity.GetActivityStreamsBcc(); bcc != nil {
- for iter := bcc.Begin(); iter != bcc.End(); iter = iter.Next() {
- var err error
- actorsAndCollections, err = appendToActorsAndCollectionsIRIs(
- iter, actorsAndCollections,
- )
- if err != nil {
- return nil, err
- }
- }
- }
-
- if audience := activity.GetActivityStreamsAudience(); audience != nil {
- for iter := audience.Begin(); iter != audience.End(); iter = iter.Next() {
- var err error
- actorsAndCollections, err = appendToActorsAndCollectionsIRIs(
- iter, actorsAndCollections,
- )
- if err != nil {
- return nil, err
- }
- }
- }
-
- // PRE-SORTING
-
- // If the pre-delivery sort function is defined,
- // call it now so that implementations can sort
- // delivery order to their preferences.
- if a.DeliveryRecipientPreSort != nil {
- actorsAndCollections = a.DeliveryRecipientPreSort(actorsAndCollections)
- }
-
- // We now need to dereference the actor or collection
- // IRIs to derive inboxes that we can POST requests to.
- var (
- inboxes = make([]*url.URL, 0, len(actorsAndCollections))
- derefdEntries = make(map[string]struct{}, len(actorsAndCollections))
- )
-
- // First check if the implemented database logic
- // can return any of these inboxes without having
- // to make remote dereference calls (much cheaper).
- for _, actorOrCollection := range actorsAndCollections {
- actorOrCollectionStr := actorOrCollection.String()
- if _, derefd := derefdEntries[actorOrCollectionStr]; derefd {
- // Ignore potential duplicates
- // we've already derefd to inbox(es).
- continue
- }
-
- // BEGIN LOCK
- unlock, err := a.db.Lock(ctx, actorOrCollection)
- if err != nil {
- return nil, err
- }
-
- // Try to get inbox(es) for this actor or collection.
- gotInboxes, err := a.db.InboxesForIRI(ctx, actorOrCollection)
-
- // END LOCK
- unlock()
-
- if err != nil {
- return nil, err
- }
-
- if len(gotInboxes) == 0 {
- // No hit(s).
- continue
- }
-
- // We have one or more hits.
- inboxes = append(inboxes, gotInboxes...)
-
- // Mark this actor or collection as deref'd.
- derefdEntries[actorOrCollectionStr] = struct{}{}
- }
-
- // Now look for any remaining actors/collections
- // that weren't already dereferenced into inboxes
- // with db calls; find these by making deref calls
- // to remote instances.
- //
- // First get a transport to do the http calls.
- t, err := a.common.NewTransport(ctx, outboxIRI, goFedUserAgent())
- if err != nil {
- return nil, err
- }
-
- // Make HTTP calls to unpack collection IRIs into
- // Actor IRIs and then into Actor types, ignoring
- // actors or collections we've already deref'd.
- actorsFromRemote, err := a.resolveActors(
- ctx,
- t,
- actorsAndCollections,
- derefdEntries,
- 0, a.s2s.MaxDeliveryRecursionDepth(ctx),
- )
- if err != nil {
- return nil, err
- }
-
- // Release no-longer-needed collections.
- clear(derefdEntries)
- clear(actorsAndCollections)
-
- // Extract inbox IRI from each deref'd Actor (if any).
- inboxesFromRemote, err := actorsToInboxIRIs(actorsFromRemote)
- if err != nil {
- return nil, err
- }
-
- // Combine db-discovered inboxes and remote-discovered
- // inboxes into a final list of destination inboxes.
- inboxes = append(inboxes, inboxesFromRemote...)
-
- // POST FILTERING
-
- // Do a final pass of the inboxes to:
- //
- // 1. Deduplicate entries.
- // 2. Ensure that the list of inboxes doesn't
- // contain the inbox of whoever the outbox
- // belongs to, no point delivering to oneself.
- //
- // To do this we first need to get the
- // inbox IRI of this outbox's Actor.
-
- // BEGIN LOCK
- unlock, err := a.db.Lock(ctx, outboxIRI)
- if err != nil {
- return nil, err
- }
-
- // Get the IRI of the Actor who owns this outbox.
- outboxActorIRI, err := a.db.ActorForOutbox(ctx, outboxIRI)
-
- // END LOCK
- unlock()
-
- if err != nil {
- return nil, err
- }
-
- // BEGIN LOCK
- unlock, err = a.db.Lock(ctx, outboxActorIRI)
- if err != nil {
- return nil, err
- }
-
- // Now get the Actor who owns this outbox.
- outboxActor, err := a.db.Get(ctx, outboxActorIRI)
-
- // END LOCK
- unlock()
-
- if err != nil {
- return nil, err
- }
-
- // Extract the inbox IRI for the outbox Actor.
- inboxOfOutboxActor, err := getInbox(outboxActor)
- if err != nil {
- return nil, err
- }
-
- // Deduplicate the final inboxes slice, and filter
- // out of the inbox of this outbox actor (if present).
- inboxes = filterInboxIRIs(inboxes, inboxOfOutboxActor)
-
- // Now that we've derived inboxes to deliver
- // the activity to, strip off any bto or bcc
- // recipients, as per the AP spec requirements.
- stripHiddenRecipients(activity)
-
- // All done!
- return inboxes, nil
-}
-
-// resolveActors takes a list of Actor id URIs and returns them as concrete
-// instances of actorObject. It attempts to apply recursively when it encounters
-// a target that is a Collection or OrderedCollection.
-//
-// Any IRI strings in the ignores map will be skipped (use this when
-// you've already dereferenced some of the actorAndCollectionIRIs).
-//
-// If maxDepth is zero or negative, then recursion is infinitely applied.
-//
-// If a recipient is a Collection or OrderedCollection, then the server MUST
-// dereference the collection, WITH the user's credentials.
-//
-// Note that this also applies to CollectionPage and OrderedCollectionPage.
-func (a *SideEffectActor) resolveActors(
- ctx context.Context,
- t Transport,
- actorAndCollectionIRIs []*url.URL,
- ignores map[string]struct{},
- depth, maxDepth int,
-) ([]vocab.Type, error) {
- if maxDepth > 0 && depth >= maxDepth {
- // Hit our max depth.
- return nil, nil
- }
-
- if len(actorAndCollectionIRIs) == 0 {
- // Nothing to do.
- return nil, nil
- }
-
- // Optimistically assume 1:1 mapping of IRIs to actors.
- actors := make([]vocab.Type, 0, len(actorAndCollectionIRIs))
-
- // Deref each actorOrCollectionIRI if not ignored.
- for _, actorOrCollectionIRI := range actorAndCollectionIRIs {
- _, ignore := ignores[actorOrCollectionIRI.String()]
- if ignore {
- // Don't try to
- // deref this one.
- continue
- }
-
- // TODO: Determine if more logic is needed here for
- // inaccessible collections owned by peer servers.
- actor, more, err := a.dereferenceForResolvingInboxes(ctx, t, actorOrCollectionIRI)
- if err != nil {
- // Missing recipient -- skip.
- continue
- }
-
- if actor != nil {
- // Got a hit.
- actors = append(actors, actor)
- }
-
- // If this was a collection, get more.
- recurActors, err := a.resolveActors(
- ctx,
- t,
- more,
- ignores,
- depth+1, maxDepth,
- )
- if err != nil {
- return nil, err
- }
-
- actors = append(actors, recurActors...)
- }
-
- return actors, nil
-}
-
-// dereferenceForResolvingInboxes dereferences an IRI solely for finding an
-// actor's inbox IRI to deliver to.
-//
-// The returned actor could be nil, if it wasn't an actor (ex: a Collection or
-// OrderedCollection).
-func (a *SideEffectActor) dereferenceForResolvingInboxes(c context.Context, t Transport, actorIRI *url.URL) (actor vocab.Type, moreActorIRIs []*url.URL, err error) {
- var resp *http.Response
- resp, err = t.Dereference(c, actorIRI)
- if err != nil {
- return
- }
- var m map[string]interface{}
- m, err = readActivityPubResp(resp)
- if err != nil {
- return
- }
- actor, err = streams.ToType(c, m)
- if err != nil {
- return
- }
- // Attempt to see if the 'actor' is really some sort of type that has
- // an 'items' or 'orderedItems' property.
- if v, ok := actor.(itemser); ok {
- if i := v.GetActivityStreamsItems(); i != nil {
- for iter := i.Begin(); iter != i.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- moreActorIRIs = append(moreActorIRIs, id)
- }
- }
- actor = nil
- } else if v, ok := actor.(orderedItemser); ok {
- if i := v.GetActivityStreamsOrderedItems(); i != nil {
- for iter := i.Begin(); iter != i.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- moreActorIRIs = append(moreActorIRIs, id)
- }
- }
- actor = nil
- }
- return
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/social_protocol.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/social_protocol.go
deleted file mode 100644
index 1f882b284..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/social_protocol.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package pub
-
-import (
- "context"
- "net/http"
-
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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 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
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/social_wrapped_callbacks.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/social_wrapped_callbacks.go
deleted file mode 100644
index 9f93a9c65..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/social_wrapped_callbacks.go
+++ /dev/null
@@ -1,534 +0,0 @@
-package pub
-
-import (
- "context"
- "fmt"
- "net/url"
-
- "codeberg.org/superseriousbusiness/activity/streams"
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-// 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 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
-
- // Sidechannel data -- this is set at request handling time. These must
- // be set before the callbacks are used.
-
- // db is the Database the SocialWrappedCallbacks should use. It must be
- // set before calling the callbacks.
- db Database
- // outboxIRI is the outboxIRI that is handling this callback.
- outboxIRI *url.URL
- // rawActivity is the JSON map literal received when deserializing the
- // request body.
- rawActivity map[string]interface{}
- // clock is the server's clock.
- clock Clock
- // newTransport creates a new Transport.
- newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
- // undeliverable is a sidechannel out, indicating if the handled activity
- // should not be delivered to a peer.
- //
- // Its provided default value will always be used when a custom function
- // is called.
- undeliverable *bool
-}
-
-// callbacks returns the WrappedCallbacks members into a single interface slice
-// for use in streams.Resolver callbacks.
-//
-// 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 {
- switch fn.(type) {
- default:
- continue
- case func(context.Context, vocab.ActivityStreamsCreate) error:
- enableCreate = false
- case func(context.Context, vocab.ActivityStreamsUpdate) error:
- enableUpdate = false
- case func(context.Context, vocab.ActivityStreamsDelete) error:
- enableDelete = false
- case func(context.Context, vocab.ActivityStreamsFollow) error:
- enableFollow = false
- case func(context.Context, vocab.ActivityStreamsAdd) error:
- enableAdd = false
- case func(context.Context, vocab.ActivityStreamsRemove) error:
- enableRemove = false
- case func(context.Context, vocab.ActivityStreamsLike) error:
- enableLike = false
- case func(context.Context, vocab.ActivityStreamsUndo) error:
- enableUndo = false
- case func(context.Context, vocab.ActivityStreamsBlock) error:
- enableBlock = false
- }
- }
- if enableCreate {
- fns = append(fns, w.create)
- }
- 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.
-func (w SocialWrappedCallbacks) create(c context.Context, a vocab.ActivityStreamsCreate) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Obtain all actor IRIs.
- actors := a.GetActivityStreamsActor()
- createActorIds := make(map[string]*url.URL)
- if actors != nil {
- createActorIds = make(map[string]*url.URL, actors.Len())
- for iter := actors.Begin(); iter != actors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- createActorIds[id.String()] = id
- }
- }
- // Obtain each object's 'attributedTo' IRIs.
- objectAttributedToIds := make([]map[string]*url.URL, op.Len())
- for i := range objectAttributedToIds {
- objectAttributedToIds[i] = make(map[string]*url.URL)
- }
- for i := 0; i < op.Len(); i++ {
- t := op.At(i).GetType()
- attrToer, ok := t.(attributedToer)
- if !ok {
- continue
- }
- attr := attrToer.GetActivityStreamsAttributedTo()
- if attr == nil {
- attr = streams.NewActivityStreamsAttributedToProperty()
- attrToer.SetActivityStreamsAttributedTo(attr)
- }
- for iter := attr.Begin(); iter != attr.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objectAttributedToIds[i][id.String()] = id
- }
- }
- // Put all missing actor IRIs onto all object attributedTo properties.
- for k, v := range createActorIds {
- for i, attributedToMap := range objectAttributedToIds {
- if _, ok := attributedToMap[k]; !ok {
- t := op.At(i).GetType()
- attrToer, ok := t.(attributedToer)
- if !ok {
- continue
- }
- attr := attrToer.GetActivityStreamsAttributedTo()
- attr.AppendIRI(v)
- }
- }
- }
- // Put all missing object attributedTo IRIs onto the actor property
- // if there is one.
- if actors != nil {
- for _, attributedToMap := range objectAttributedToIds {
- for k, v := range attributedToMap {
- if _, ok := createActorIds[k]; !ok {
- actors.AppendIRI(v)
- }
- }
- }
- }
- // Copy over the 'to', 'bto', 'cc', 'bcc', and 'audience' recipients
- // between the activity and all child objects and vice versa.
- if err := normalizeRecipients(a); err != nil {
- return err
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(i int) error {
- obj := op.At(i).GetType()
- id, err := GetId(obj)
- if err != nil {
- return err
- }
- var unlock func()
- unlock, err = w.db.Lock(c, id)
- if err != nil {
- return err
- }
- defer unlock()
- if err := w.db.Create(c, obj); err != nil {
- return err
- }
- return nil
- }
- // Persist all objects we've created, which will include sensitive
- // recipients such as 'bcc' and 'bto'.
- for i := 0; i < op.Len(); i++ {
- if err := loopFn(i); err != nil {
- return err
- }
- }
- if w.Create != nil {
- return w.Create(c, a)
- }
- return nil
-}
-
-// update implements the social Update activity side effects.
-func (w SocialWrappedCallbacks) update(c context.Context, a vocab.ActivityStreamsUpdate) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Obtain all object ids, which should be owned by this server.
- objIds := make([]*url.URL, 0, op.Len())
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objIds = append(objIds, id)
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(idx int, loopId *url.URL) error {
- unlock, err := w.db.Lock(c, loopId)
- if err != nil {
- return err
- }
- defer unlock()
- t, err := w.db.Get(c, loopId)
- if err != nil {
- return err
- }
- m, err := t.Serialize()
- if err != nil {
- return err
- }
- // Copy over new top-level values.
- objType := op.At(idx).GetType()
- if objType == nil {
- return fmt.Errorf("object at index %d is not a literal type value", idx)
- }
- newM, err := objType.Serialize()
- if err != nil {
- return err
- }
- for k, v := range newM {
- m[k] = v
- }
- // Delete top-level values where the raw Activity had nils.
- for k, v := range w.rawActivity {
- if _, ok := m[k]; v == nil && ok {
- delete(m, k)
- }
- }
- newT, err := streams.ToType(c, m)
- if err != nil {
- return err
- }
- if err = w.db.Update(c, newT); err != nil {
- return err
- }
- return nil
- }
- for i, id := range objIds {
- if err := loopFn(i, id); err != nil {
- return err
- }
- }
- if w.Update != nil {
- return w.Update(c, a)
- }
- return nil
-}
-
-// deleteFn implements the social Delete activity side effects.
-func (w SocialWrappedCallbacks) deleteFn(c context.Context, a vocab.ActivityStreamsDelete) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Obtain all object ids, which should be owned by this server.
- objIds := make([]*url.URL, 0, op.Len())
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objIds = append(objIds, id)
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(idx int, loopId *url.URL) error {
- unlock, err := w.db.Lock(c, loopId)
- if err != nil {
- return err
- }
- defer unlock()
- t, err := w.db.Get(c, loopId)
- if err != nil {
- return err
- }
- tomb := toTombstone(t, loopId, w.clock.Now())
- if err := w.db.Update(c, tomb); err != nil {
- return err
- }
- return nil
- }
- for i, id := range objIds {
- if err := loopFn(i, id); err != nil {
- return err
- }
- }
- if w.Delete != nil {
- return w.Delete(c, a)
- }
- return nil
-}
-
-// follow implements the social Follow activity side effects.
-func (w SocialWrappedCallbacks) follow(c context.Context, a vocab.ActivityStreamsFollow) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- if w.Follow != nil {
- return w.Follow(c, a)
- }
- return nil
-}
-
-// add implements the social Add activity side effects.
-func (w SocialWrappedCallbacks) add(c context.Context, a vocab.ActivityStreamsAdd) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- target := a.GetActivityStreamsTarget()
- if target == nil || target.Len() == 0 {
- return ErrTargetRequired
- }
- if err := add(c, op, target, w.db); err != nil {
- return err
- }
- if w.Add != nil {
- return w.Add(c, a)
- }
- return nil
-}
-
-// remove implements the social Remove activity side effects.
-func (w SocialWrappedCallbacks) remove(c context.Context, a vocab.ActivityStreamsRemove) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- target := a.GetActivityStreamsTarget()
- if target == nil || target.Len() == 0 {
- return ErrTargetRequired
- }
- if err := remove(c, op, target, w.db); err != nil {
- return err
- }
- if w.Remove != nil {
- return w.Remove(c, a)
- }
- return nil
-}
-
-// like implements the social Like activity side effects.
-func (w SocialWrappedCallbacks) like(c context.Context, a vocab.ActivityStreamsLike) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- // Get this actor's IRI.
- unlock, err := w.db.Lock(c, w.outboxIRI)
- if err != nil {
- return err
- }
- // WARNING: Unlock not deferred.
- actorIRI, err := w.db.ActorForOutbox(c, w.outboxIRI)
- unlock() // unlock even on error
- if err != nil {
- return err
- }
- // Unlock must be called by now and every branch above.
- //
- // Now obtain this actor's 'liked' collection.
- unlock, err = w.db.Lock(c, actorIRI)
- if err != nil {
- return err
- }
- defer unlock()
- liked, err := w.db.Liked(c, actorIRI)
- if err != nil {
- return err
- }
- likedItems := liked.GetActivityStreamsItems()
- if likedItems == nil {
- likedItems = streams.NewActivityStreamsItemsProperty()
- liked.SetActivityStreamsItems(likedItems)
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- objId, err := ToId(iter)
- if err != nil {
- return err
- }
- likedItems.PrependIRI(objId)
- }
- err = w.db.Update(c, liked)
- if err != nil {
- return err
- }
- if w.Like != nil {
- return w.Like(c, a)
- }
- return nil
-}
-
-// undo implements the social Undo activity side effects.
-func (w SocialWrappedCallbacks) undo(c context.Context, a vocab.ActivityStreamsUndo) error {
- *w.undeliverable = false
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- actors := a.GetActivityStreamsActor()
- if err := mustHaveActivityActorsMatchObjectActors(c, actors, op, w.newTransport, w.outboxIRI); err != nil {
- return err
- }
- if w.Undo != nil {
- return w.Undo(c, a)
- }
- return nil
-}
-
-// block implements the social Block activity side effects.
-func (w SocialWrappedCallbacks) block(c context.Context, a vocab.ActivityStreamsBlock) error {
- *w.undeliverable = true
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return ErrObjectRequired
- }
- if w.Block != nil {
- return w.Block(c, a)
- }
- return nil
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/transport.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/transport.go
deleted file mode 100644
index 101ff5c07..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/transport.go
+++ /dev/null
@@ -1,219 +0,0 @@
-package pub
-
-import (
- "bytes"
- "context"
- "crypto"
- "encoding/json"
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "sync"
-
- "github.com/go-fed/httpsig"
-)
-
-const (
- // acceptHeaderValue is the Accept header value indicating that the
- // response should contain an ActivityStreams object.
- acceptHeaderValue = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
-)
-
-// isSuccess returns true if the HTTP status code is either OK, Created, or
-// Accepted.
-func isSuccess(code int) bool {
- return code == http.StatusOK ||
- code == http.StatusCreated ||
- code == http.StatusAccepted
-}
-
-// 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.
-type Transport interface {
- // Dereference fetches the ActivityStreams object located at this IRI with
- // a GET request. Note that Response will only be returned on status = OK.
- Dereference(c context.Context, iri *url.URL) (*http.Response, error)
-
- // Deliver sends an ActivityStreams object.
- Deliver(c context.Context, obj map[string]interface{}, to *url.URL) error
-
- // BatchDeliver sends an ActivityStreams object to multiple recipients.
- BatchDeliver(c context.Context, obj map[string]interface{}, recipients []*url.URL) error
-}
-
-// Transport must be implemented by HttpSigTransport.
-var _ Transport = &HttpSigTransport{}
-
-// 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.
-type HttpSigTransport struct {
- client HttpClient
- appAgent string
- gofedAgent string
- clock Clock
- getSigner httpsig.Signer
- getSignerMu *sync.Mutex
- postSigner httpsig.Signer
- postSignerMu *sync.Mutex
- pubKeyId string
- privKey crypto.PrivateKey
-}
-
-// 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(
- client HttpClient,
- appAgent string,
- clock Clock,
- getSigner, postSigner httpsig.Signer,
- pubKeyId string,
- privKey crypto.PrivateKey) *HttpSigTransport {
- return &HttpSigTransport{
- client: client,
- appAgent: appAgent,
- gofedAgent: goFedUserAgent(),
- clock: clock,
- getSigner: getSigner,
- getSignerMu: &sync.Mutex{},
- postSigner: postSigner,
- postSignerMu: &sync.Mutex{},
- pubKeyId: pubKeyId,
- privKey: privKey,
- }
-}
-
-// 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) (*http.Response, error) {
- req, err := http.NewRequest("GET", iri.String(), nil)
- if err != nil {
- return nil, err
- }
- req = req.WithContext(c)
- req.Header.Add(acceptHeader, acceptHeaderValue)
- req.Header.Add("Accept-Charset", "utf-8")
- req.Header.Add("Date", h.clock.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
- req.Header.Add("User-Agent", fmt.Sprintf("%s %s", h.appAgent, h.gofedAgent))
- req.Header.Set("Host", iri.Host)
- h.getSignerMu.Lock()
- err = h.getSigner.SignRequest(h.privKey, h.pubKeyId, req, nil)
- h.getSignerMu.Unlock()
- if err != nil {
- return nil, err
- }
- resp, err := h.client.Do(req)
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != http.StatusOK {
- _ = resp.Body.Close()
- return nil, fmt.Errorf("GET request to %s failed (%d): %s", iri.String(), resp.StatusCode, resp.Status)
- }
- return resp, nil
-}
-
-// Deliver sends a POST request with an HTTP Signature.
-func (h HttpSigTransport) Deliver(c context.Context, data map[string]interface{}, to *url.URL) error {
- b, err := json.Marshal(data)
- if err != nil {
- return err
- }
- return h.deliver(c, b, to)
-}
-
-// BatchDeliver sends concurrent POST requests. Returns an error if any of the requests had an error.
-func (h HttpSigTransport) BatchDeliver(c context.Context, data map[string]interface{}, recipients []*url.URL) error {
- b, err := json.Marshal(data)
- if err != nil {
- return err
- }
- var wg sync.WaitGroup
- errCh := make(chan error, len(recipients))
- for _, recipient := range recipients {
- wg.Add(1)
- go func(r *url.URL) {
- defer wg.Done()
- if err := h.deliver(c, b, r); err != nil {
- errCh <- err
- }
- }(recipient)
- }
- wg.Wait()
- errs := make([]string, 0, len(recipients))
-outer:
- for {
- select {
- case e := <-errCh:
- errs = append(errs, e.Error())
- default:
- break outer
- }
- }
- if len(errs) > 0 {
- return fmt.Errorf("batch deliver had at least one failure: %s", strings.Join(errs, "; "))
- }
- return nil
-}
-
-func (h HttpSigTransport) deliver(c context.Context, b []byte, to *url.URL) error {
- req, err := http.NewRequest("POST", to.String(), bytes.NewReader(b))
- if err != nil {
- return err
- }
- req = req.WithContext(c)
- req.Header.Add(contentTypeHeader, contentTypeHeaderValue)
- req.Header.Add("Accept-Charset", "utf-8")
- req.Header.Add("Date", h.clock.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
- req.Header.Add("User-Agent", fmt.Sprintf("%s %s", h.appAgent, h.gofedAgent))
- req.Header.Set("Host", to.Host)
- h.postSignerMu.Lock()
- err = h.postSigner.SignRequest(h.privKey, h.pubKeyId, req, b)
- h.postSignerMu.Unlock()
- if err != nil {
- return err
- }
- resp, err := h.client.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- if !isSuccess(resp.StatusCode) {
- return fmt.Errorf("POST request to %s failed (%d): %s", to.String(), resp.StatusCode, resp.Status)
- }
- return nil
-}
-
-// HttpClient sends http requests, and is an abstraction only needed by the
-// HttpSigTransport. The standard library's Client satisfies this interface.
-type HttpClient interface {
- Do(req *http.Request) (*http.Response, error)
-}
-
-// HttpClient must be implemented by http.Client.
-var _ HttpClient = &http.Client{}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/util.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/util.go
deleted file mode 100644
index 1a5ea7640..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/util.go
+++ /dev/null
@@ -1,1077 +0,0 @@
-package pub
-
-import (
- "bytes"
- "context"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- "codeberg.org/superseriousbusiness/activity/streams"
- "codeberg.org/superseriousbusiness/activity/streams/vocab"
-)
-
-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")
-)
-
-// activityStreamsMediaTypes contains all of the accepted ActivityStreams media
-// types. Generated at init time.
-var activityStreamsMediaTypes []string
-
-func init() {
- activityStreamsMediaTypes = []string{
- "application/activity+json",
- }
- jsonLdType := "application/ld+json"
- for _, semi := range []string{";", " ;", " ; ", "; "} {
- for _, profile := range []string{
- "profile=https://www.w3.org/ns/activitystreams",
- "profile=\"https://www.w3.org/ns/activitystreams\"",
- } {
- activityStreamsMediaTypes = append(
- activityStreamsMediaTypes,
- fmt.Sprintf("%s%s%s", jsonLdType, semi, profile))
- }
- }
-}
-
-// headerIsActivityPubMediaType returns true if the header string contains one
-// of the accepted ActivityStreams media types.
-//
-// Note we don't try to build a comprehensive parser and instead accept a
-// tolerable amount of whitespace since the HTTP specification is ambiguous
-// about the format and significance of whitespace.
-func headerIsActivityPubMediaType(header string) bool {
- for _, mediaType := range activityStreamsMediaTypes {
- if strings.Contains(header, mediaType) {
- return true
- }
- }
- return false
-}
-
-const (
- // The Content-Type header.
- contentTypeHeader = "Content-Type"
- // The Accept header.
- acceptHeader = "Accept"
-)
-
-// readActivityPubReq reads ActivityPub data from an incoming request, handling body close.
-func readActivityPubReq(req *http.Request) (map[string]interface{}, error) {
- // Ensure closed when done.
- defer req.Body.Close()
-
- var m map[string]interface{}
-
- // Wrap body in a JSON decoder.
- dec := json.NewDecoder(req.Body)
-
- // Decode JSON body as "raw" AP data map.
- if err := dec.Decode(&m); err != nil {
- return nil, err
- }
-
- // Perform a final second decode to ensure no trailing
- // garbage data or second JSON value (indicates malformed).
- if err := dec.Decode(&struct{}{}); err != io.EOF {
- return nil, errors.New("trailing data after json")
- }
-
- return m, nil
-}
-
-// readActivityPubResp reads ActivityPub data from a dereference response, handling media type check and body close.
-func readActivityPubResp(resp *http.Response) (map[string]interface{}, error) {
- // Ensure closed when done.
- defer resp.Body.Close()
-
- // Check the incoming response media type is the expected ActivityPub content-type.
- if mediaType := resp.Header.Get("Content-Type"); !headerIsActivityPubMediaType(mediaType) {
- return nil, fmt.Errorf("%s %s resp was not ActivityPub media type: %s", resp.Request.Method, resp.Request.URL, mediaType)
- }
-
- var m map[string]interface{}
-
- // Wrap body in a JSON decoder.
- dec := json.NewDecoder(resp.Body)
-
- // Decode JSON body as "raw" AP data map.
- if err := dec.Decode(&m); err != nil {
- return nil, err
- }
-
- // Perform a final second decode to ensure no trailing
- // garbage data or second JSON value (indicates malformed).
- if err := dec.Decode(&struct{}{}); err != io.EOF {
- return nil, errors.New("trailing data after json")
- }
-
- return m, nil
-}
-
-// isActivityPubPost returns true if the request is a POST request that has the
-// ActivityStreams content type header
-func isActivityPubPost(r *http.Request) bool {
- return r.Method == "POST" && headerIsActivityPubMediaType(r.Header.Get(contentTypeHeader))
-}
-
-// isActivityPubGet returns true if the request is a GET request that has the
-// ActivityStreams content type header
-func isActivityPubGet(r *http.Request) bool {
- return r.Method == "GET" && headerIsActivityPubMediaType(r.Header.Get(acceptHeader))
-}
-
-// dedupeOrderedItems deduplicates the 'orderedItems' within an ordered
-// collection type. Deduplication happens by the 'id' property.
-func dedupeOrderedItems(oc orderedItemser) error {
- oi := oc.GetActivityStreamsOrderedItems()
- if oi == nil {
- return nil
- }
- seen := make(map[string]bool, oi.Len())
- for i := 0; i < oi.Len(); {
- var id *url.URL
-
- iter := oi.At(i)
- asType := iter.GetType()
- if asType != nil {
- var err error
- id, err = GetId(asType)
- if err != nil {
- return err
- }
- } else if iter.IsIRI() {
- id = iter.GetIRI()
- } else {
- return fmt.Errorf("element %d in OrderedCollection does not have an ID nor is an IRI", i)
- }
- if seen[id.String()] {
- oi.Remove(i)
- } else {
- seen[id.String()] = true
- i++
- }
- }
- return nil
-}
-
-const (
- // The Location header
- locationHeader = "Location"
- // Contains the ActivityStreams Content-Type value.
- contentTypeHeaderValue = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
- // The Date header.
- dateHeader = "Date"
- // The Digest header.
- digestHeader = "Digest"
- // The delimiter used in the Digest header.
- digestDelimiter = "="
- // SHA-256 string for the Digest header.
- sha256Digest = "SHA-256"
-)
-
-// addResponseHeaders sets headers needed in the HTTP response, such but not
-// limited to the Content-Type, Date, and Digest headers.
-func addResponseHeaders(h http.Header, c Clock, responseContent []byte) {
- h.Set(contentTypeHeader, contentTypeHeaderValue)
- // RFC 7231 ยง7.1.1.2
- h.Set(dateHeader, c.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
- // RFC 3230 and RFC 5843
- var b bytes.Buffer
- b.WriteString(sha256Digest)
- b.WriteString(digestDelimiter)
- hashed := sha256.Sum256(responseContent)
- b.WriteString(base64.StdEncoding.EncodeToString(hashed[:]))
- h.Set(digestHeader, b.String())
-}
-
-// IdProperty is a property that can readily have its id obtained
-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
-}
-
-// ToId returns an IdProperty's id.
-func ToId(i IdProperty) (*url.URL, error) {
- if i.GetType() != nil {
- return GetId(i.GetType())
- } else if i.IsIRI() {
- return i.GetIRI(), nil
- }
- return nil, fmt.Errorf("cannot determine id of activitystreams property")
-}
-
-// 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 GetId(t vocab.Type) (*url.URL, error) {
- if id := t.GetJSONLDId(); id != nil {
- return id.Get(), nil
- } else if h, ok := t.(hrefer); ok {
- if href := h.GetActivityStreamsHref(); href != nil {
- return href.Get(), nil
- }
- }
- return nil, fmt.Errorf("cannot determine id of activitystreams value")
-}
-
-// getInboxForwardingValues obtains the 'inReplyTo', 'object', 'target', and
-// 'tag' values on an ActivityStreams value.
-func getInboxForwardingValues(o vocab.Type) (t []vocab.Type, iri []*url.URL) {
- // 'inReplyTo'
- if i, ok := o.(inReplyToer); ok {
- if irt := i.GetActivityStreamsInReplyTo(); irt != nil {
- for iter := irt.Begin(); iter != irt.End(); iter = iter.Next() {
- if tv := iter.GetType(); tv != nil {
- t = append(t, tv)
- } else {
- iri = append(iri, iter.GetIRI())
- }
- }
- }
- }
- // 'tag'
- if i, ok := o.(tagger); ok {
- if tag := i.GetActivityStreamsTag(); tag != nil {
- for iter := tag.Begin(); iter != tag.End(); iter = iter.Next() {
- if tv := iter.GetType(); tv != nil {
- t = append(t, tv)
- } else {
- iri = append(iri, iter.GetIRI())
- }
- }
- }
- }
- // 'object'
- if i, ok := o.(objecter); ok {
- if obj := i.GetActivityStreamsObject(); obj != nil {
- for iter := obj.Begin(); iter != obj.End(); iter = iter.Next() {
- if tv := iter.GetType(); tv != nil {
- t = append(t, tv)
- } else {
- iri = append(iri, iter.GetIRI())
- }
- }
- }
- }
- // 'target'
- if i, ok := o.(targeter); ok {
- if tar := i.GetActivityStreamsTarget(); tar != nil {
- for iter := tar.Begin(); iter != tar.End(); iter = iter.Next() {
- if tv := iter.GetType(); tv != nil {
- t = append(t, tv)
- } else {
- iri = append(iri, iter.GetIRI())
- }
- }
- }
- }
- return
-}
-
-// wrapInCreate will automatically wrap the provided object in a Create
-// activity. This will copy over the 'to', 'bto', 'cc', 'bcc', and 'audience'
-// properties. It will also copy over the published time if present.
-func wrapInCreate(ctx context.Context, o vocab.Type, actor *url.URL) (c vocab.ActivityStreamsCreate, err error) {
- c = streams.NewActivityStreamsCreate()
- // Object property
- oProp := streams.NewActivityStreamsObjectProperty()
- oProp.AppendType(o)
- c.SetActivityStreamsObject(oProp)
- // Actor Property
- actorProp := streams.NewActivityStreamsActorProperty()
- actorProp.AppendIRI(actor)
- c.SetActivityStreamsActor(actorProp)
- // Published Property
- if v, ok := o.(publisheder); ok {
- c.SetActivityStreamsPublished(v.GetActivityStreamsPublished())
- }
- // Copying over properties.
- if v, ok := o.(toer); ok {
- if to := v.GetActivityStreamsTo(); to != nil {
- activityTo := streams.NewActivityStreamsToProperty()
- for iter := to.Begin(); iter != to.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- activityTo.AppendIRI(id)
- }
- c.SetActivityStreamsTo(activityTo)
- }
- }
- if v, ok := o.(btoer); ok {
- if bto := v.GetActivityStreamsBto(); bto != nil {
- activityBto := streams.NewActivityStreamsBtoProperty()
- for iter := bto.Begin(); iter != bto.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- activityBto.AppendIRI(id)
- }
- c.SetActivityStreamsBto(activityBto)
- }
- }
- if v, ok := o.(ccer); ok {
- if cc := v.GetActivityStreamsCc(); cc != nil {
- activityCc := streams.NewActivityStreamsCcProperty()
- for iter := cc.Begin(); iter != cc.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- activityCc.AppendIRI(id)
- }
- c.SetActivityStreamsCc(activityCc)
- }
- }
- if v, ok := o.(bccer); ok {
- if bcc := v.GetActivityStreamsBcc(); bcc != nil {
- activityBcc := streams.NewActivityStreamsBccProperty()
- for iter := bcc.Begin(); iter != bcc.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- activityBcc.AppendIRI(id)
- }
- c.SetActivityStreamsBcc(activityBcc)
- }
- }
- if v, ok := o.(audiencer); ok {
- if aud := v.GetActivityStreamsAudience(); aud != nil {
- activityAudience := streams.NewActivityStreamsAudienceProperty()
- for iter := aud.Begin(); iter != aud.End(); iter = iter.Next() {
- var id *url.URL
- id, err = ToId(iter)
- if err != nil {
- return
- }
- activityAudience.AppendIRI(id)
- }
- c.SetActivityStreamsAudience(activityAudience)
- }
- }
- return
-}
-
-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"
- publicJsonLD = "Public"
- publicJsonLDAS = "as:Public"
-)
-
-// IsPublic determines if an IRI string is the Public collection as defined in
-// the spec, including JSON-LD compliant collections.
-func IsPublic(s string) bool {
- return s == PublicActivityPubIRI || s == publicJsonLD || s == publicJsonLDAS
-}
-
-// Derives an ID URI from the given IdProperty and, if it's not the
-// magic AP Public IRI, appends it to the actorsAndCollections slice.
-func appendToActorsAndCollectionsIRIs(
- iter IdProperty,
- actorsAndCollections []*url.URL,
-) ([]*url.URL, error) {
- id, err := ToId(iter)
- if err != nil {
- return nil, err
- }
-
- // Ignore Public IRI as we
- // can't deliver to it directly.
- if !IsPublic(id.String()) {
- actorsAndCollections = append(actorsAndCollections, id)
- }
-
- return actorsAndCollections, nil
-}
-
-// actorsToInboxIRIs extracts the 'inbox' IRIs from actor types.
-func actorsToInboxIRIs(t []vocab.Type) (u []*url.URL, err error) {
- for _, elem := range t {
- var iri *url.URL
- iri, err = getInbox(elem)
- if err != nil {
- return
- }
- u = append(u, iri)
- }
- return
-}
-
-// getInbox extracts the 'inbox' IRI from an actor type.
-func getInbox(t vocab.Type) (u *url.URL, err error) {
- ib, ok := t.(inboxer)
- if !ok {
- err = fmt.Errorf("actor type %T has no inbox", t)
- return
- }
- inbox := ib.GetActivityStreamsInbox()
- return ToId(inbox)
-}
-
-// filterInboxIRIs will deduplicate the given inboxes
-// slice, while also leaving out any filtered IRIs.
-func filterInboxIRIs(
- inboxes []*url.URL,
- filtered ...*url.URL,
-) []*url.URL {
- // Prepopulate the ignored map with each filtered IRI.
- ignored := make(map[string]struct{}, len(filtered)+len(inboxes))
- for _, filteredIRI := range filtered {
- ignored[filteredIRI.String()] = struct{}{}
- }
-
- deduped := make([]*url.URL, 0, len(inboxes))
- for _, inbox := range inboxes {
- inboxStr := inbox.String()
- _, ignore := ignored[inboxStr]
- if ignore {
- // We already included
- // this URI in out, or
- // we should ignore it.
- continue
- }
-
- // Include this IRI in output, and
- // add entry to the ignored map to
- // ensure we don't include it again.
- deduped = append(deduped, inbox)
- ignored[inboxStr] = struct{}{}
- }
-
- return deduped
-}
-
-// stripHiddenRecipients removes "bto" and "bcc" from the activity.
-//
-// Note that this requirement of the specification is under "Section 6: Client
-// to Server Interactions", the Social API, and not the Federative API.
-func stripHiddenRecipients(activity Activity) {
- activity.SetActivityStreamsBto(nil)
- activity.SetActivityStreamsBcc(nil)
- op := activity.GetActivityStreamsObject()
- if op != nil {
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- if v, ok := iter.GetType().(btoer); ok {
- v.SetActivityStreamsBto(nil)
- }
- if v, ok := iter.GetType().(bccer); ok {
- v.SetActivityStreamsBcc(nil)
- }
- }
- }
-}
-
-// mustHaveActivityOriginMatchObjects ensures that the Host in the activity id
-// IRI matches all of the Hosts in the object id IRIs.
-func mustHaveActivityOriginMatchObjects(a Activity) error {
- originIRI, err := GetId(a)
- if err != nil {
- return err
- }
- originHost := originIRI.Host
- op := a.GetActivityStreamsObject()
- if op == nil || op.Len() == 0 {
- return nil
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- iri, err := ToId(iter)
- if err != nil {
- return err
- }
- if originHost != iri.Host {
- return fmt.Errorf("object %q: not in activity origin", iri)
- }
- }
- return nil
-}
-
-// normalizeRecipients ensures the activity and object have the same 'to',
-// 'bto', 'cc', 'bcc', and 'audience' properties. Copy the Activity's recipients
-// to objects, and the objects to the activity, but does NOT copy objects'
-// recipients to each other.
-func normalizeRecipients(a vocab.ActivityStreamsCreate) error {
- // Phase 0: Acquire all recipients on the activity.
- //
- // Obtain the actorTo map
- actorToMap := make(map[string]*url.URL)
- actorTo := a.GetActivityStreamsTo()
- if actorTo == nil {
- actorTo = streams.NewActivityStreamsToProperty()
- a.SetActivityStreamsTo(actorTo)
- }
- for iter := actorTo.Begin(); iter != actorTo.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- actorToMap[id.String()] = id
- }
- // Obtain the actorBto map
- actorBtoMap := make(map[string]*url.URL)
- actorBto := a.GetActivityStreamsBto()
- if actorBto == nil {
- actorBto = streams.NewActivityStreamsBtoProperty()
- a.SetActivityStreamsBto(actorBto)
- }
- for iter := actorBto.Begin(); iter != actorBto.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- actorBtoMap[id.String()] = id
- }
- // Obtain the actorCc map
- actorCcMap := make(map[string]*url.URL)
- actorCc := a.GetActivityStreamsCc()
- if actorCc == nil {
- actorCc = streams.NewActivityStreamsCcProperty()
- a.SetActivityStreamsCc(actorCc)
- }
- for iter := actorCc.Begin(); iter != actorCc.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- actorCcMap[id.String()] = id
- }
- // Obtain the actorBcc map
- actorBccMap := make(map[string]*url.URL)
- actorBcc := a.GetActivityStreamsBcc()
- if actorBcc == nil {
- actorBcc = streams.NewActivityStreamsBccProperty()
- a.SetActivityStreamsBcc(actorBcc)
- }
- for iter := actorBcc.Begin(); iter != actorBcc.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- actorBccMap[id.String()] = id
- }
- // Obtain the actorAudience map
- actorAudienceMap := make(map[string]*url.URL)
- actorAudience := a.GetActivityStreamsAudience()
- if actorAudience == nil {
- actorAudience = streams.NewActivityStreamsAudienceProperty()
- a.SetActivityStreamsAudience(actorAudience)
- }
- for iter := actorAudience.Begin(); iter != actorAudience.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- actorAudienceMap[id.String()] = id
- }
- // Obtain the objects maps for each recipient type.
- o := a.GetActivityStreamsObject()
- objsTo := make([]map[string]*url.URL, o.Len())
- objsBto := make([]map[string]*url.URL, o.Len())
- objsCc := make([]map[string]*url.URL, o.Len())
- objsBcc := make([]map[string]*url.URL, o.Len())
- objsAudience := make([]map[string]*url.URL, o.Len())
- for i := 0; i < o.Len(); i++ {
- iter := o.At(i)
- // Phase 1: Acquire all existing recipients on the object.
- //
- // Object to
- objsTo[i] = make(map[string]*url.URL)
- var oTo vocab.ActivityStreamsToProperty
- if tr, ok := iter.GetType().(toer); !ok {
- return fmt.Errorf("the Create object at %d has no 'to' property", i)
- } else {
- oTo = tr.GetActivityStreamsTo()
- if oTo == nil {
- oTo = streams.NewActivityStreamsToProperty()
- tr.SetActivityStreamsTo(oTo)
- }
- }
- for iter := oTo.Begin(); iter != oTo.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objsTo[i][id.String()] = id
- }
- // Object bto
- objsBto[i] = make(map[string]*url.URL)
- var oBto vocab.ActivityStreamsBtoProperty
- if tr, ok := iter.GetType().(btoer); !ok {
- return fmt.Errorf("the Create object at %d has no 'bto' property", i)
- } else {
- oBto = tr.GetActivityStreamsBto()
- if oBto == nil {
- oBto = streams.NewActivityStreamsBtoProperty()
- tr.SetActivityStreamsBto(oBto)
- }
- }
- for iter := oBto.Begin(); iter != oBto.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objsBto[i][id.String()] = id
- }
- // Object cc
- objsCc[i] = make(map[string]*url.URL)
- var oCc vocab.ActivityStreamsCcProperty
- if tr, ok := iter.GetType().(ccer); !ok {
- return fmt.Errorf("the Create object at %d has no 'cc' property", i)
- } else {
- oCc = tr.GetActivityStreamsCc()
- if oCc == nil {
- oCc = streams.NewActivityStreamsCcProperty()
- tr.SetActivityStreamsCc(oCc)
- }
- }
- for iter := oCc.Begin(); iter != oCc.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objsCc[i][id.String()] = id
- }
- // Object bcc
- objsBcc[i] = make(map[string]*url.URL)
- var oBcc vocab.ActivityStreamsBccProperty
- if tr, ok := iter.GetType().(bccer); !ok {
- return fmt.Errorf("the Create object at %d has no 'bcc' property", i)
- } else {
- oBcc = tr.GetActivityStreamsBcc()
- if oBcc == nil {
- oBcc = streams.NewActivityStreamsBccProperty()
- tr.SetActivityStreamsBcc(oBcc)
- }
- }
- for iter := oBcc.Begin(); iter != oBcc.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objsBcc[i][id.String()] = id
- }
- // Object audience
- objsAudience[i] = make(map[string]*url.URL)
- var oAudience vocab.ActivityStreamsAudienceProperty
- if tr, ok := iter.GetType().(audiencer); !ok {
- return fmt.Errorf("the Create object at %d has no 'audience' property", i)
- } else {
- oAudience = tr.GetActivityStreamsAudience()
- if oAudience == nil {
- oAudience = streams.NewActivityStreamsAudienceProperty()
- tr.SetActivityStreamsAudience(oAudience)
- }
- }
- for iter := oAudience.Begin(); iter != oAudience.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- objsAudience[i][id.String()] = id
- }
- // Phase 2: Apply missing recipients to the object from the
- // activity.
- //
- // Activity to -> Object to
- for k, v := range actorToMap {
- if _, ok := objsTo[i][k]; !ok {
- oTo.AppendIRI(v)
- }
- }
- // Activity bto -> Object bto
- for k, v := range actorBtoMap {
- if _, ok := objsBto[i][k]; !ok {
- oBto.AppendIRI(v)
- }
- }
- // Activity cc -> Object cc
- for k, v := range actorCcMap {
- if _, ok := objsCc[i][k]; !ok {
- oCc.AppendIRI(v)
- }
- }
- // Activity bcc -> Object bcc
- for k, v := range actorBccMap {
- if _, ok := objsBcc[i][k]; !ok {
- oBcc.AppendIRI(v)
- }
- }
- // Activity audience -> Object audience
- for k, v := range actorAudienceMap {
- if _, ok := objsAudience[i][k]; !ok {
- oAudience.AppendIRI(v)
- }
- }
- }
- // Phase 3: Apply missing recipients to the activity from the objects.
- //
- // Object to -> Activity to
- for i := 0; i < len(objsTo); i++ {
- for k, v := range objsTo[i] {
- if _, ok := actorToMap[k]; !ok {
- actorTo.AppendIRI(v)
- }
- }
- }
- // Object bto -> Activity bto
- for i := 0; i < len(objsBto); i++ {
- for k, v := range objsBto[i] {
- if _, ok := actorBtoMap[k]; !ok {
- actorBto.AppendIRI(v)
- }
- }
- }
- // Object cc -> Activity cc
- for i := 0; i < len(objsCc); i++ {
- for k, v := range objsCc[i] {
- if _, ok := actorCcMap[k]; !ok {
- actorCc.AppendIRI(v)
- }
- }
- }
- // Object bcc -> Activity bcc
- for i := 0; i < len(objsBcc); i++ {
- for k, v := range objsBcc[i] {
- if _, ok := actorBccMap[k]; !ok {
- actorBcc.AppendIRI(v)
- }
- }
- }
- // Object audience -> Activity audience
- for i := 0; i < len(objsAudience); i++ {
- for k, v := range objsAudience[i] {
- if _, ok := actorAudienceMap[k]; !ok {
- actorAudience.AppendIRI(v)
- }
- }
- }
- return nil
-}
-
-// toTombstone creates a Tombstone object for the given ActivityStreams value.
-func toTombstone(obj vocab.Type, id *url.URL, now time.Time) vocab.ActivityStreamsTombstone {
- tomb := streams.NewActivityStreamsTombstone()
- // id property
- idProp := streams.NewJSONLDIdProperty()
- idProp.Set(id)
- tomb.SetJSONLDId(idProp)
- // formerType property
- former := streams.NewActivityStreamsFormerTypeProperty()
- tomb.SetActivityStreamsFormerType(former)
- // Populate Former Type
- former.AppendXMLSchemaString(obj.GetTypeName())
- // Copy over the published property if it existed
- if pubber, ok := obj.(publisheder); ok {
- if pub := pubber.GetActivityStreamsPublished(); pub != nil {
- tomb.SetActivityStreamsPublished(pub)
- }
- }
- // Copy over the updated property if it existed
- if upder, ok := obj.(updateder); ok {
- if upd := upder.GetActivityStreamsUpdated(); upd != nil {
- tomb.SetActivityStreamsUpdated(upd)
- }
- }
- // Set deleted time to now.
- deleted := streams.NewActivityStreamsDeletedProperty()
- deleted.Set(now)
- tomb.SetActivityStreamsDeleted(deleted)
- return tomb
-}
-
-// mustHaveActivityActorsMatchObjectActors ensures that the actors on types in
-// the 'object' property are all listed in the 'actor' property.
-func mustHaveActivityActorsMatchObjectActors(c context.Context,
- actors vocab.ActivityStreamsActorProperty,
- op vocab.ActivityStreamsObjectProperty,
- newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error),
- boxIRI *url.URL,
-) error {
- activityActorMap := make(map[string]bool, actors.Len())
- for iter := actors.Begin(); iter != actors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- activityActorMap[id.String()] = true
- }
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- iri, err := ToId(iter)
- if err != nil {
- return err
- }
- // Attempt to dereference the IRI, regardless whether it is a
- // type or IRI
- tport, err := newTransport(c, boxIRI, goFedUserAgent())
- if err != nil {
- return err
- }
- resp, err := tport.Dereference(c, iri)
- if err != nil {
- return err
- }
- m, err := readActivityPubResp(resp)
- if err != nil {
- return err
- }
- t, err := streams.ToType(c, m)
- if err != nil {
- return err
- }
- ac, ok := t.(actorer)
- if !ok {
- return fmt.Errorf("cannot verify actors: object value has no 'actor' property")
- }
- objActors := ac.GetActivityStreamsActor()
- for iter := objActors.Begin(); iter != objActors.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- if !activityActorMap[id.String()] {
- return fmt.Errorf("activity does not have all actors from its object's actors")
- }
- }
- }
- return nil
-}
-
-// add implements the logic of adding object ids to a target Collection or
-// OrderedCollection. This logic is shared by both the C2S and S2S protocols.
-func add(c context.Context,
- op vocab.ActivityStreamsObjectProperty,
- target vocab.ActivityStreamsTargetProperty,
- db Database,
-) error {
- opIds := make([]*url.URL, 0, op.Len())
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- opIds = append(opIds, id)
- }
- targetIds := make([]*url.URL, 0, op.Len())
- for iter := target.Begin(); iter != target.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- targetIds = append(targetIds, id)
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(t *url.URL) error {
- unlock, err := db.Lock(c, t)
- if err != nil {
- return err
- }
- defer unlock()
- if owns, err := db.Owns(c, t); err != nil {
- return err
- } else if !owns {
- return nil
- }
- tp, err := db.Get(c, t)
- if err != nil {
- return err
- }
- if streams.IsOrExtendsActivityStreamsOrderedCollection(tp) {
- oi, ok := tp.(orderedItemser)
- if !ok {
- return fmt.Errorf("type extending from OrderedCollection cannot convert to orderedItemser interface")
- }
- oiProp := oi.GetActivityStreamsOrderedItems()
- if oiProp == nil {
- oiProp = streams.NewActivityStreamsOrderedItemsProperty()
- oi.SetActivityStreamsOrderedItems(oiProp)
- }
- for _, objId := range opIds {
- oiProp.AppendIRI(objId)
- }
- } else if streams.IsOrExtendsActivityStreamsCollection(tp) {
- i, ok := tp.(itemser)
- if !ok {
- return fmt.Errorf("type extending from Collection cannot convert to itemser interface")
- }
- iProp := i.GetActivityStreamsItems()
- if iProp == nil {
- iProp = streams.NewActivityStreamsItemsProperty()
- i.SetActivityStreamsItems(iProp)
- }
- for _, objId := range opIds {
- iProp.AppendIRI(objId)
- }
- } else {
- return fmt.Errorf("target in Add is neither a Collection nor an OrderedCollection")
- }
- err = db.Update(c, tp)
- if err != nil {
- return err
- }
- return nil
- }
- for _, t := range targetIds {
- if err := loopFn(t); err != nil {
- return err
- }
- }
- return nil
-}
-
-// remove implements the logic of removing object ids to a target Collection or
-// OrderedCollection. This logic is shared by both the C2S and S2S protocols.
-func remove(c context.Context,
- op vocab.ActivityStreamsObjectProperty,
- target vocab.ActivityStreamsTargetProperty,
- db Database,
-) error {
- opIds := make(map[string]bool, op.Len())
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- opIds[id.String()] = true
- }
- targetIds := make([]*url.URL, 0, op.Len())
- for iter := target.Begin(); iter != target.End(); iter = iter.Next() {
- id, err := ToId(iter)
- if err != nil {
- return err
- }
- targetIds = append(targetIds, id)
- }
- // Create anonymous loop function to be able to properly scope the defer
- // for the database lock at each iteration.
- loopFn := func(t *url.URL) error {
- unlock, err := db.Lock(c, t)
- if err != nil {
- return err
- }
- defer unlock()
- if owns, err := db.Owns(c, t); err != nil {
- return err
- } else if !owns {
- return nil
- }
- tp, err := db.Get(c, t)
- if err != nil {
- return err
- }
- if streams.IsOrExtendsActivityStreamsOrderedCollection(tp) {
- oi, ok := tp.(orderedItemser)
- if !ok {
- return fmt.Errorf("type extending from OrderedCollection cannot convert to orderedItemser interface")
- }
- oiProp := oi.GetActivityStreamsOrderedItems()
- if oiProp != nil {
- for i := 0; i < oiProp.Len(); /*Conditional*/ {
- id, err := ToId(oiProp.At(i))
- if err != nil {
- return err
- }
- if opIds[id.String()] {
- oiProp.Remove(i)
- } else {
- i++
- }
- }
- }
- } else if streams.IsOrExtendsActivityStreamsCollection(tp) {
- i, ok := tp.(itemser)
- if !ok {
- return fmt.Errorf("type extending from Collection cannot convert to itemser interface")
- }
- iProp := i.GetActivityStreamsItems()
- if iProp != nil {
- for i := 0; i < iProp.Len(); /*Conditional*/ {
- id, err := ToId(iProp.At(i))
- if err != nil {
- return err
- }
- if opIds[id.String()] {
- iProp.Remove(i)
- } else {
- i++
- }
- }
- }
- } else {
- return fmt.Errorf("target in Remove is neither a Collection nor an OrderedCollection")
- }
- err = db.Update(c, tp)
- if err != nil {
- return err
- }
- return nil
- }
- for _, t := range targetIds {
- if err := loopFn(t); err != nil {
- return err
- }
- }
- return nil
-}
-
-// clearSensitiveFields removes the 'bto' and 'bcc' entries on the given value
-// and recursively on every 'object' property value.
-func clearSensitiveFields(obj vocab.Type) {
- if t, ok := obj.(btoer); ok {
- t.SetActivityStreamsBto(nil)
- }
- if t, ok := obj.(bccer); ok {
- t.SetActivityStreamsBcc(nil)
- }
- if t, ok := obj.(objecter); ok {
- op := t.GetActivityStreamsObject()
- if op != nil {
- for iter := op.Begin(); iter != op.End(); iter = iter.Next() {
- clearSensitiveFields(iter.GetType())
- }
- }
- }
-}
-
-// requestId forms an ActivityPub id based on the HTTP request. Always assumes
-// that the id is HTTPS.
-func requestId(r *http.Request, scheme string) *url.URL {
- id := r.URL
- id.Host = r.Host
- id.Scheme = scheme
- return id
-}
diff --git a/vendor/codeberg.org/superseriousbusiness/activity/pub/version.go b/vendor/codeberg.org/superseriousbusiness/activity/pub/version.go
deleted file mode 100644
index 23b958ce5..000000000
--- a/vendor/codeberg.org/superseriousbusiness/activity/pub/version.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package pub
-
-import (
- "fmt"
-)
-
-const (
- // Version string, used in the User-Agent
- version = "v1.0.0"
-)
-
-// goFedUserAgent returns the user agent string for the go-fed library.
-func goFedUserAgent() string {
- return fmt.Sprintf("(go-fed/activity %s)", version)
-}