fixes issue #100 - can't follow from pubgate

this moves the unmarshaling of a remote actor out into a new helper which
accounts for the possibility of a context being a list or a single entity.
i.e. a string or an object.

basics tests are provided for both situations

also go fmt'd the file activitypub.go
This commit is contained in:
Rob Loranger 2019-05-20 14:41:26 -07:00
parent 3986c8eec1
commit ff2d3fc3d5
No known key found for this signature in database
GPG key ID: D6F1633A4F0903B8
3 changed files with 87 additions and 8 deletions

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"go.formatTool": "goimports"
}

View file

@ -17,6 +17,13 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"time"
"github.com/go-sql-driver/mysql" "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/writeas/activity/streams" "github.com/writeas/activity/streams"
@ -26,12 +33,6 @@ import (
"github.com/writeas/web-core/activitypub" "github.com/writeas/web-core/activitypub"
"github.com/writeas/web-core/activitystreams" "github.com/writeas/web-core/activitystreams"
"github.com/writeas/web-core/log" "github.com/writeas/web-core/log"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"time"
) )
const ( const (
@ -647,8 +648,7 @@ func getActor(app *app, actorIRI string) (*activitystreams.Person, *RemoteUser,
log.Error("Unable to get actor! %v", err) log.Error("Unable to get actor! %v", err)
return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't fetch actor."} return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't fetch actor."}
} }
if err := json.Unmarshal(actorResp, &actor); err != nil { if err := unmarshalActor(actorResp, actor); err != nil {
// FIXME: Hubzilla has an object for the Actor's url: cannot unmarshal object into Go struct field Person.url of type string
log.Error("Unable to unmarshal actor! %v", err) log.Error("Unable to unmarshal actor! %v", err)
return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't parse actor."} return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't parse actor."}
} }
@ -663,3 +663,48 @@ func getActor(app *app, actorIRI string) (*activitystreams.Person, *RemoteUser,
} }
return actor, remoteUser, nil return actor, remoteUser, nil
} }
// unmarshal actor normalizes the actor response to conform to
// the type Person from github.com/writeas/web-core/activitysteams
//
// some implementations return different context field types
// this converts any non-slice contexts into a slice
func unmarshalActor(actorResp []byte, actor *activitystreams.Person) error {
// FIXME: Hubzilla has an object for the Actor's url: cannot unmarshal object into Go struct field Person.url of type string
// flexActor overrides the Context field to allow
// all valid representations during unmarshal
flexActor := struct {
activitystreams.Person
Context json.RawMessage `json:"@context,omitempty"`
}{}
if err := json.Unmarshal(actorResp, &flexActor); err != nil {
return err
}
actor.Endpoints = flexActor.Endpoints
actor.Followers = flexActor.Followers
actor.Following = flexActor.Following
actor.ID = flexActor.ID
actor.Icon = flexActor.Icon
actor.Inbox = flexActor.Inbox
actor.Name = flexActor.Name
actor.Outbox = flexActor.Outbox
actor.PreferredUsername = flexActor.PreferredUsername
actor.PublicKey = flexActor.PublicKey
actor.Summary = flexActor.Summary
actor.Type = flexActor.Type
actor.URL = flexActor.URL
func(val interface{}) {
switch val.(type) {
case []interface{}:
// already a slice, do nothing
actor.Context = val.([]interface{})
default:
actor.Context = []interface{}{val}
}
}(flexActor.Context)
return nil
}

31
activitypub_test.go Normal file
View file

@ -0,0 +1,31 @@
package writefreely
import (
"testing"
"github.com/writeas/web-core/activitystreams"
)
var actorTestTable = []struct {
Name string
Resp []byte
}{
{
"Context as a string",
[]byte(`{"@context":"https://www.w3.org/ns/activitystreams"}`),
},
{
"Context as a list",
[]byte(`{"@context":["one string", "two strings"]}`),
},
}
func TestUnmarshalActor(t *testing.T) {
for _, tc := range actorTestTable {
actor := activitystreams.Person{}
err := unmarshalActor(tc.Resp, &actor)
if err != nil {
t.Errorf("%s failed with error %s", tc.Name, err)
}
}
}