mirror of
https://github.com/owncast/owncast.git
synced 2024-11-22 21:03:19 +03:00
236 lines
6.8 KiB
Go
236 lines
6.8 KiB
Go
package resolvers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"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 := io.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, actor may not be valid: "+publicKeyIRI)
|
|
}
|
|
|
|
if !resolved {
|
|
err = errors.New("error resolving publickey from iri, actor may not be valid: " + publicKeyIRI)
|
|
}
|
|
|
|
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
|
|
}
|