diff --git a/internal/ap/resolve.go b/internal/ap/resolve.go index 4ff4f87fc..20a858900 100644 --- a/internal/ap/resolve.go +++ b/internal/ap/resolve.go @@ -27,6 +27,7 @@ "github.com/superseriousbusiness/activity/pub" "github.com/superseriousbusiness/activity/streams" + "github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/gotosocial/internal/gtserror" ) @@ -56,6 +57,35 @@ func putMap(m map[string]any) { mapPool.Put(m) } +// bytesToType tries to parse the given bytes slice +// as a JSON ActivityPub type, failing if the input +// bytes are not parseable as JSON, or do not parse +// to an ActivityPub that we can understand. +// +// The given map pointer will also be populated with +// the parsed JSON, to allow further processing. +func bytesToType( + ctx context.Context, + b []byte, + raw map[string]any, +) (vocab.Type, error) { + // Unmarshal the raw JSON bytes into a "raw" map. + // This will fail if the input is not parseable + // as JSON; eg., a remote has returned HTML as a + // fallback response to an ActivityPub JSON request. + if err := json.Unmarshal(b, &raw); err != nil { + return nil, gtserror.NewfAt(3, "error unmarshalling bytes into json: %w", err) + } + + // Resolve an ActivityStreams type. + t, err := streams.ToType(ctx, raw) + if err != nil { + return nil, gtserror.NewfAt(3, "error resolving json into ap vocab type: %w", err) + } + + return t, nil +} + // ResolveActivity is a util function for pulling a pub.Activity type out of an incoming request body, // returning the resolved activity type, error and whether to accept activity (false = transient i.e. ignore). func ResolveIncomingActivity(r *http.Request) (pub.Activity, bool, gtserror.WithCode) { @@ -121,15 +151,11 @@ func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) { // destination. raw := getMap() - // Unmarshal the raw JSON data in a "raw" JSON map. - if err := json.Unmarshal(b, &raw); err != nil { - return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err) - } - - // Resolve an ActivityStreams type from JSON. - t, err := streams.ToType(ctx, raw) + // Convert raw bytes to an AP type. + // This will also populate the map. + t, err := bytesToType(ctx, b, raw) if err != nil { - return nil, gtserror.Newf("error resolving json into ap vocab type: %w", err) + return nil, gtserror.SetWrongType(err) } // Attempt to cast as Statusable. @@ -166,15 +192,11 @@ func ResolveAccountable(ctx context.Context, b []byte) (Accountable, error) { // destination. raw := getMap() - // Unmarshal the raw JSON data in a "raw" JSON map. - if err := json.Unmarshal(b, &raw); err != nil { - return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err) - } - - // Resolve an ActivityStreams type from JSON. - t, err := streams.ToType(ctx, raw) + // Convert raw bytes to an AP type. + // This will also populate the map. + t, err := bytesToType(ctx, b, raw) if err != nil { - return nil, gtserror.Newf("error resolving json into ap vocab type: %w", err) + return nil, gtserror.SetWrongType(err) } // Attempt to cast as Statusable. diff --git a/internal/ap/resolve_test.go b/internal/ap/resolve_test.go index 0b2c8fb0c..bc32af7e4 100644 --- a/internal/ap/resolve_test.go +++ b/internal/ap/resolve_test.go @@ -47,6 +47,29 @@ func (suite *ResolveTestSuite) TestResolveDocumentAsAccountable() { suite.Nil(accountable) } +func (suite *ResolveTestSuite) TestResolveHTMLAsAccountable() { + b := []byte(` +