157 lines
4.4 KiB
Go

package controllers
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/requests"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
const (
outboxPageSize = 50
)
// OutboxHandler will handle requests for the local ActivityPub outbox.
func OutboxHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
var response interface{}
var err error
if r.URL.Query().Get("page") != "" {
response, err = getOutboxPage(r.URL.Query().Get("page"), r)
} else {
response, err = getInitialOutboxHandler(r)
}
if response == nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err != nil {
_, _ = w.Write([]byte(err.Error()))
w.WriteHeader(http.StatusInternalServerError)
return
}
pathComponents := strings.Split(r.URL.Path, "/")
accountName := pathComponents[3]
actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
publicKey := crypto.GetPublicKey(actorIRI)
if err := requests.WriteStreamResponse(response.(vocab.Type), w, publicKey); err != nil {
log.Errorln("unable to write stream response for outbox handler", err)
}
}
// ActorObjectHandler will handle the request for a single ActivityPub object.
func ActorObjectHandler(w http.ResponseWriter, r *http.Request) {
object, _, _, err := persistence.GetObjectByIRI(r.URL.Path)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
// responses.WriteSimpleResponse(w, false, err.Error())
}
if _, err := w.Write([]byte(object)); err != nil {
log.Errorln(err)
}
}
func getInitialOutboxHandler(r *http.Request) (vocab.ActivityStreamsOrderedCollection, error) {
collection := streams.NewActivityStreamsOrderedCollection()
idProperty := streams.NewJSONLDIdProperty()
id, err := createPageURL(r, nil)
if err != nil {
return nil, errors.Wrap(err, "unable to create followers page property")
}
idProperty.SetIRI(id)
collection.SetJSONLDId(idProperty)
totalPosts, err := persistence.GetOutboxPostCount()
if err != nil {
return nil, errors.Wrap(err, "unable to get outbox post count")
}
totalItemsProperty := streams.NewActivityStreamsTotalItemsProperty()
totalItemsProperty.Set(int(totalPosts))
collection.SetActivityStreamsTotalItems(totalItemsProperty)
first := streams.NewActivityStreamsFirstProperty()
page := "1"
firstIRI, err := createPageURL(r, &page)
if err != nil {
return nil, errors.Wrap(err, "unable to create first page property")
}
first.SetIRI(firstIRI)
collection.SetActivityStreamsFirst(first)
return collection, nil
}
func getOutboxPage(page string, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error) {
pageInt, err := strconv.Atoi(page)
if err != nil {
return nil, errors.Wrap(err, "unable to parse page number")
}
postCount, err := persistence.GetOutboxPostCount()
if err != nil {
return nil, errors.Wrap(err, "unable to get outbox post count")
}
collectionPage := streams.NewActivityStreamsOrderedCollectionPage()
idProperty := streams.NewJSONLDIdProperty()
id, err := createPageURL(r, &page)
if err != nil {
return nil, errors.Wrap(err, "unable to create followers page ID")
}
idProperty.SetIRI(id)
collectionPage.SetJSONLDId(idProperty)
orderedItems := streams.NewActivityStreamsOrderedItemsProperty()
outboxItems, err := persistence.GetOutbox(outboxPageSize, (pageInt-1)*outboxPageSize)
if err != nil {
return nil, errors.Wrap(err, "unable to get federation followers")
}
orderedItems.AppendActivityStreamsOrderedCollection(outboxItems)
collectionPage.SetActivityStreamsOrderedItems(orderedItems)
partOf := streams.NewActivityStreamsPartOfProperty()
partOfIRI, err := createPageURL(r, nil)
if err != nil {
return nil, errors.Wrap(err, "unable to create partOf property for outbox page")
}
partOf.SetIRI(partOfIRI)
collectionPage.SetActivityStreamsPartOf(partOf)
if pageInt*followersPageSize < int(postCount) {
next := streams.NewActivityStreamsNextProperty()
nextPage := fmt.Sprintf("%d", pageInt+1)
nextIRI, err := createPageURL(r, &nextPage)
if err != nil {
return nil, errors.Wrap(err, "unable to create next page property")
}
next.SetIRI(nextIRI)
collectionPage.SetActivityStreamsNext(next)
}
return collectionPage, nil
}