diff --git a/activitypub/apmodels/actor.go b/activitypub/apmodels/actor.go index 9b335d59e..5a00aa188 100644 --- a/activitypub/apmodels/actor.go +++ b/activitypub/apmodels/actor.go @@ -78,6 +78,25 @@ func MakeActorFromService(service vocab.ActivityStreamsService) ActivityPubActor return apActor } +// MakeActorFromApplication takes a full ActivityPub application and returns +// our internal representation of an actor. +func MakeActorFromApplication(application vocab.ActivityStreamsApplication) ActivityPubActor { + apActor := ActivityPubActor{ + ActorIri: application.GetJSONLDId().Get(), + Inbox: application.GetActivityStreamsInbox().GetIRI(), + Name: application.GetActivityStreamsName().Begin().GetXMLSchemaString(), + Username: application.GetActivityStreamsPreferredUsername().GetXMLSchemaString(), + FullUsername: GetFullUsernameFromApplication(application), + W3IDSecurityV1PublicKey: application.GetW3IDSecurityV1PublicKey(), + } + + if application.GetActivityStreamsIcon() != nil && application.GetActivityStreamsIcon().Len() > 0 && application.GetActivityStreamsIcon().At(0).GetActivityStreamsImage() != nil { + apActor.Image = application.GetActivityStreamsIcon().At(0).GetActivityStreamsImage().GetActivityStreamsUrl().Begin().GetIRI() + } + + return apActor +} + // MakeActorPropertyWithID will return an actor property filled with the provided IRI. func MakeActorPropertyWithID(idIRI *url.URL) vocab.ActivityStreamsActorProperty { actor := streams.NewActivityStreamsActorProperty() @@ -238,6 +257,15 @@ func GetFullUsernameFromService(person vocab.ActivityStreamsService) string { return fullUsername } +// GetFullUsernameFromApplication will return the user@host.tld formatted user given a service object. +func GetFullUsernameFromApplication(person vocab.ActivityStreamsApplication) string { + hostname := person.GetJSONLDId().GetIRI().Hostname() + username := person.GetActivityStreamsPreferredUsername().GetXMLSchemaString() + fullUsername := fmt.Sprintf("%s@%s", username, hostname) + + return fullUsername +} + func addMetadataLinkToProfile(profile vocab.ActivityStreamsService, name string, url string) { attachments := profile.GetActivityStreamsAttachment() if attachments == nil { diff --git a/activitypub/resolvers/resolve.go b/activitypub/resolvers/resolve.go index dc0d00396..df7fa4df8 100644 --- a/activitypub/resolvers/resolve.go +++ b/activitypub/resolvers/resolve.go @@ -76,6 +76,7 @@ func ResolveIRI(c context.Context, iri string, callbacks ...interface{}) error { 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) @@ -87,39 +88,77 @@ func GetResolvedActorFromActorProperty(actor vocab.ActivityStreamsActorProperty) 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); e != nil { + 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 } } - return apActor, errors.Wrap(err, "unable to resolve actor from actor property") + 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 } - if e := ResolveIRI(context.Background(), personOrServiceIRI, personCallback, serviceCallback); e != 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 } - return apActor, errors.Wrap(err, "unable to resolve actor from IRI string: "+personOrServiceIRI) + 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 }