From 6cbfb30afa479a47ce1beeb99300f2cba07cf619 Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Sun, 13 Dec 2020 23:25:58 +0100 Subject: [PATCH] Support custom schemes for handlers This allows clients to serve data over HTTP or HTTPS, which should only be done for development purposes. --- pub/base_actor.go | 28 ++++++++++++++++++++++++++-- pub/handlers.go | 19 ++++++++++++++++++- pub/util.go | 4 ++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/pub/base_actor.go b/pub/base_actor.go index ab1f220..61192c5 100644 --- a/pub/base_actor.go +++ b/pub/base_actor.go @@ -162,7 +162,19 @@ func NewCustomActor(delegate DelegateActor, // 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 @@ -222,7 +234,7 @@ func (b *baseActor) PostInbox(c context.Context, w http.ResponseWriter, r *http. // 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) + 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 @@ -298,7 +310,19 @@ func (b *baseActor) GetInbox(c context.Context, w http.ResponseWriter, r *http.R // 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 @@ -343,7 +367,7 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http } // The HTTP request steps are complete, complete the rest of the outbox // and delivery process. - outboxId := requestId(r) + 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. diff --git a/pub/handlers.go b/pub/handlers.go index 4443a42..a2ad2b2 100644 --- a/pub/handlers.go +++ b/pub/handlers.go @@ -32,14 +32,31 @@ type HandlerFunc func(c context.Context, w http.ResponseWriter, r *http.Request) // 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. +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) + id := requestId(r, scheme) // Lock and obtain a copy of the requested ActivityStreams value err = db.Lock(c, id) if err != nil { diff --git a/pub/util.go b/pub/util.go index af078c5..942e937 100644 --- a/pub/util.go +++ b/pub/util.go @@ -987,9 +987,9 @@ func clearSensitiveFields(obj vocab.Type) { // requestId forms an ActivityPub id based on the HTTP request. Always assumes // that the id is HTTPS. -func requestId(r *http.Request) *url.URL { +func requestId(r *http.Request, scheme string) *url.URL { id := r.URL id.Host = r.Host - id.Scheme = "https" + id.Scheme = scheme return id }