You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
6.8 KiB
236 lines
6.8 KiB
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(http.MethodGet, 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 external actor property to a |
|
// fully populated internal actor representation. |
|
func GetResolvedActorFromActorProperty(actor vocab.ActivityStreamsActorProperty) (apmodels.ActivityPubActor, error) { |
|
var err error |
|
var apActor apmodels.ActivityPubActor |
|
resolved := false |
|
|
|
if !actor.Empty() && actor.Len() > 0 && actor.At(0) != nil { |
|
// Explicitly use only the first actor that might be listed. |
|
actorObjectOrIRI := actor.At(0) |
|
var actorEntity apmodels.ExternalEntity |
|
|
|
// If the actor is an unresolved IRI then we need to resolve it. |
|
if actorObjectOrIRI.IsIRI() { |
|
iri := actorObjectOrIRI.GetIRI().String() |
|
return GetResolvedActorFromIRI(iri) |
|
} |
|
|
|
if actorObjectOrIRI.IsActivityStreamsPerson() { |
|
actorEntity = actorObjectOrIRI.GetActivityStreamsPerson() |
|
} else if actorObjectOrIRI.IsActivityStreamsService() { |
|
actorEntity = actorObjectOrIRI.GetActivityStreamsService() |
|
} else if actorObjectOrIRI.IsActivityStreamsApplication() { |
|
actorEntity = actorObjectOrIRI.GetActivityStreamsApplication() |
|
} else { |
|
err = errors.New("unrecognized external ActivityPub type: " + actorObjectOrIRI.Name()) |
|
return apActor, err |
|
} |
|
|
|
// If any of the resolution or population failed then return the error. |
|
if err != nil { |
|
return apActor, err |
|
} |
|
|
|
// Convert the external AP entity into an internal actor representation. |
|
apa, e := apmodels.MakeActorFromExernalAPEntity(actorEntity) |
|
if apa != nil { |
|
apActor = *apa |
|
resolved = true |
|
} |
|
err = e |
|
} |
|
|
|
if !resolved && err == nil { |
|
err = errors.New("unknown error resolving actor from property value") |
|
} |
|
|
|
return apActor, err |
|
} |
|
|
|
// GetResolvedPublicKeyFromIRI will resolve a publicKey IRI string to a vocab.W3IDSecurityV1PublicKey. |
|
func GetResolvedPublicKeyFromIRI(publicKeyIRI string) (vocab.W3IDSecurityV1PublicKey, error) { |
|
var err error |
|
var pubkey vocab.W3IDSecurityV1PublicKey |
|
resolved := false |
|
|
|
personCallback := func(c context.Context, person vocab.ActivityStreamsPerson) error { |
|
if pkProp := person.GetW3IDSecurityV1PublicKey(); pkProp != nil { |
|
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() { |
|
if iter.IsW3IDSecurityV1PublicKey() { |
|
pubkey = iter.Get() |
|
resolved = true |
|
return nil |
|
} |
|
} |
|
} |
|
return errors.New("error deriving publickey from activitystreamsperson") |
|
} |
|
|
|
serviceCallback := func(c context.Context, service vocab.ActivityStreamsService) error { |
|
if pkProp := service.GetW3IDSecurityV1PublicKey(); pkProp != nil { |
|
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() { |
|
if iter.IsW3IDSecurityV1PublicKey() { |
|
pubkey = iter.Get() |
|
resolved = true |
|
return nil |
|
} |
|
} |
|
} |
|
return errors.New("error deriving publickey from activitystreamsservice") |
|
} |
|
|
|
applicationCallback := func(c context.Context, app vocab.ActivityStreamsApplication) error { |
|
if pkProp := app.GetW3IDSecurityV1PublicKey(); pkProp != nil { |
|
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() { |
|
if iter.IsW3IDSecurityV1PublicKey() { |
|
pubkey = iter.Get() |
|
resolved = true |
|
return nil |
|
} |
|
} |
|
} |
|
return errors.New("error deriving publickey from activitystreamsapp") |
|
} |
|
|
|
pubkeyCallback := func(c context.Context, pk vocab.W3IDSecurityV1PublicKey) error { |
|
pubkey = pk |
|
resolved = true |
|
return nil |
|
} |
|
|
|
if e := ResolveIRI(context.Background(), publicKeyIRI, personCallback, serviceCallback, applicationCallback, pubkeyCallback); e != nil { |
|
err = e |
|
} |
|
|
|
if err != nil { |
|
err = errors.Wrap(err, "error resolving publickey from iri") |
|
} |
|
|
|
if !resolved { |
|
err = errors.New("error resolving publickey from iri") |
|
} |
|
|
|
return pubkey, 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 { |
|
apa, e := apmodels.MakeActorFromExernalAPEntity(person) |
|
if apa != nil { |
|
apActor = *apa |
|
resolved = true |
|
} |
|
return e |
|
} |
|
|
|
serviceCallback := func(c context.Context, service vocab.ActivityStreamsService) error { |
|
apa, e := apmodels.MakeActorFromExernalAPEntity(service) |
|
if apa != nil { |
|
apActor = *apa |
|
resolved = true |
|
} |
|
return e |
|
} |
|
|
|
applicationCallback := func(c context.Context, app vocab.ActivityStreamsApplication) error { |
|
apa, e := apmodels.MakeActorFromExernalAPEntity(app) |
|
if apa != nil { |
|
apActor = *apa |
|
resolved = true |
|
} |
|
return e |
|
} |
|
|
|
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 |
|
}
|
|
|