* feat(ap): add support for shared inboxes to reduce outbound load * feat(db): refactor ap followers db into followers repository * fix(ap): use the updated activity library to pull out the shared inbox endpoint * chore(deps): point at updated build of owncast/activity * fix(ap): typeless endpoints * feat(test): update ActivityPub test to support shared inboxes * chore(test): remove unused variable * fix: feedback from review. Guard against SSRF/non-HTTPS/local and handle transaction errors
103 lines
3.3 KiB
Go
103 lines
3.3 KiB
Go
package inbox
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/go-fed/activity/streams/vocab"
|
|
"github.com/owncast/owncast/activitypub/apmodels"
|
|
"github.com/owncast/owncast/activitypub/persistence"
|
|
"github.com/owncast/owncast/activitypub/persistence/followersrepository"
|
|
"github.com/owncast/owncast/activitypub/requests"
|
|
"github.com/owncast/owncast/activitypub/resolvers"
|
|
"github.com/owncast/owncast/core/chat/events"
|
|
"github.com/owncast/owncast/core/webhooks"
|
|
"github.com/owncast/owncast/persistence/configrepository"
|
|
"github.com/pkg/errors"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsFollow) error {
|
|
configRepository := configrepository.Get()
|
|
followersRepo := followersrepository.Get()
|
|
|
|
follow, err := resolvers.MakeFollowRequest(c, activity)
|
|
if err != nil {
|
|
log.Errorln("unable to create follow inbox request", err)
|
|
return err
|
|
}
|
|
|
|
if follow == nil {
|
|
return fmt.Errorf("unable to handle request")
|
|
}
|
|
|
|
approved := !configRepository.GetFederationIsPrivate()
|
|
|
|
followRequest := *follow
|
|
|
|
if err := followersRepo.Add(followRequest, approved); err != nil {
|
|
log.Errorln("unable to save follow request", err)
|
|
return err
|
|
}
|
|
|
|
localAccountName := configRepository.GetDefaultFederationUsername()
|
|
|
|
objectIRI, err := apmodels.GetIRIStringFromObjectProperty(activity.GetActivityStreamsObject())
|
|
if err != nil {
|
|
return errors.Wrap(err, "follow activity is missing object IRI")
|
|
}
|
|
|
|
actorIRI, err := apmodels.GetIRIStringFromActorProperty(activity.GetActivityStreamsActor())
|
|
if err != nil {
|
|
return errors.Wrap(err, "follow activity is missing actor IRI")
|
|
}
|
|
|
|
actorReference := activity.GetActivityStreamsActor()
|
|
|
|
if approved {
|
|
if err := requests.SendFollowAccept(follow.Inbox, activity, localAccountName); err != nil {
|
|
log.Errorln("unable to send follow accept", err)
|
|
return err
|
|
}
|
|
go webhooks.SendFediverseEngagementFollowEvent(actorIRI)
|
|
}
|
|
|
|
// If this request is approved and we have not previously sent an action to
|
|
// chat due to a previous follow request, then do so.
|
|
hasPreviouslyhandled := true // Default so we don't send anything if it fails.
|
|
if approved {
|
|
hasPreviouslyhandled, err = persistence.HasPreviouslyHandledInboundActivity(objectIRI, actorIRI, events.FediverseEngagementFollow)
|
|
if err != nil {
|
|
log.Errorln("error checking for previously handled follow activity", err)
|
|
}
|
|
}
|
|
|
|
// Save this follow action to our activities table.
|
|
if err := persistence.SaveInboundFediverseActivity(objectIRI, actorIRI, events.FediverseEngagementFollow, time.Now()); err != nil {
|
|
return errors.Wrap(err, "unable to save inbound share/re-post activity")
|
|
}
|
|
|
|
// Send action to chat if it has not been previously handled.
|
|
if !hasPreviouslyhandled {
|
|
return handleEngagementActivity(events.FediverseEngagementFollow, false, actorReference, events.FediverseEngagementFollow)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func handleUnfollowRequest(c context.Context, activity vocab.ActivityStreamsUndo) error {
|
|
request := resolvers.MakeUnFollowRequest(c, activity)
|
|
if request == nil {
|
|
log.Errorf("unable to handle unfollow request")
|
|
return errors.New("unable to handle unfollow request")
|
|
}
|
|
|
|
unfollowRequest := *request
|
|
log.Traceln("unfollow request:", unfollowRequest)
|
|
|
|
followersRepo := followersrepository.Get()
|
|
return followersRepo.Remove(unfollowRequest)
|
|
}
|