owncast/activitypub/resolvers/resolve.go

164 lines
4.7 KiB
Go

package resolvers
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"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/core/data"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
// Resolve will translate a raw ActivityPub payload and fire the callback associated with that activity type.
func Resolve(c context.Context, data []byte, callbacks ...interface{}) error {
jsonResolver, err := streams.NewJSONResolver(callbacks...)
if err != nil {
// Something in the setup was wrong. For example, a callback has an
// unsupported signature and would never be called
return err
}
var jsonMap map[string]interface{}
if err = json.Unmarshal(data, &jsonMap); err != nil {
return err
}
log.Debugln("Resolving payload...", string(data))
// The createCallback function will be called.
err = jsonResolver.Resolve(c, jsonMap)
if err != nil && !streams.IsUnmatchedErr(err) {
// Something went wrong
return err
} else if streams.IsUnmatchedErr(err) {
// Everything went right but the callback didn't match or the ActivityStreams
// type is one that wasn't code generated.
log.Debugln("No match: ", err)
}
return nil
}
// ResolveIRI will resolve an IRI ahd call the correct callback for the resolved type.
func ResolveIRI(c context.Context, iri string, callbacks ...interface{}) error {
log.Debugln("Resolving", iri)
req, _ := http.NewRequest("GET", iri, nil)
actor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
if err := crypto.SignRequest(req, nil, actor); err != nil {
return err
}
response, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer response.Body.Close()
data, err := ioutil.ReadAll(response.Body)
if err != nil {
return err
}
// fmt.Println(string(data))
return Resolve(c, data, callbacks...)
}
// GetResolvedActorFromActorProperty resolve an actor property to a fully populated person.
func GetResolvedActorFromActorProperty(actor vocab.ActivityStreamsActorProperty) (apmodels.ActivityPubActor, error) {
var err error
var apActor apmodels.ActivityPubActor
resolved := false
personCallback := func(c context.Context, person vocab.ActivityStreamsPerson) error {
apActor = apmodels.MakeActorFromPerson(person)
return nil
}
serviceCallback := func(c context.Context, s vocab.ActivityStreamsService) error {
apActor = apmodels.MakeActorFromService(s)
return nil
}
applicationCallback := func(c context.Context, s vocab.ActivityStreamsApplication) error {
apActor = apmodels.MakeActorFromApplication(s)
resolved = true
return nil
}
for iter := actor.Begin(); iter != actor.End(); iter = iter.Next() {
if iter.IsIRI() {
iri := iter.GetIRI()
if e := ResolveIRI(context.Background(), iri.String(), personCallback, serviceCallback, applicationCallback); e != nil {
err = e
}
} else if iter.IsActivityStreamsPerson() {
person := iter.GetActivityStreamsPerson()
apActor = apmodels.MakeActorFromPerson(person)
resolved = true
} else if iter.IsActivityStreamsService() {
person := iter.GetActivityStreamsService()
apActor = apmodels.MakeActorFromService(person)
resolved = true
} else if iter.IsActivityStreamsApplication() {
person := iter.GetActivityStreamsApplication()
apActor = apmodels.MakeActorFromApplication(person)
resolved = true
}
}
if err != nil {
err = errors.Wrap(err, "error resolving actor from property value")
}
if !resolved {
err = errors.New("error resolving actor from property value")
}
return apActor, err
}
// GetResolvedActorFromIRI will resolve an IRI string to a fully populated actor.
func GetResolvedActorFromIRI(personOrServiceIRI string) (apmodels.ActivityPubActor, error) {
var err error
var apActor apmodels.ActivityPubActor
resolved := false
personCallback := func(c context.Context, person vocab.ActivityStreamsPerson) error {
apActor = apmodels.MakeActorFromPerson(person)
resolved = true
return nil
}
serviceCallback := func(c context.Context, s vocab.ActivityStreamsService) error {
apActor = apmodels.MakeActorFromService(s)
resolved = true
return nil
}
applicationCallback := func(c context.Context, s vocab.ActivityStreamsApplication) error {
apActor = apmodels.MakeActorFromApplication(s)
resolved = true
return nil
}
if e := ResolveIRI(context.Background(), personOrServiceIRI, personCallback, serviceCallback, applicationCallback); e != nil {
err = e
}
if err != nil {
err = errors.Wrap(err, "error resolving actor from property value")
}
if !resolved {
err = errors.New("error resolving actor from property value")
}
return apActor, err
}