[bugfix] Don't return Internal Server Error when searching for URIs that don't return AP JSON (#2550)
* [bugfix] Don't return Internal Server Error when searching for URIs that don't return AP JSON * don't pass map pointer
This commit is contained in:
parent
b3ba1516a7
commit
d9729e7d28
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/superseriousbusiness/activity/pub"
|
"github.com/superseriousbusiness/activity/pub"
|
||||||
"github.com/superseriousbusiness/activity/streams"
|
"github.com/superseriousbusiness/activity/streams"
|
||||||
|
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -56,6 +57,35 @@ func putMap(m map[string]any) {
|
||||||
mapPool.Put(m)
|
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,
|
// 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).
|
// 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) {
|
func ResolveIncomingActivity(r *http.Request) (pub.Activity, bool, gtserror.WithCode) {
|
||||||
|
@ -121,15 +151,11 @@ func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) {
|
||||||
// destination.
|
// destination.
|
||||||
raw := getMap()
|
raw := getMap()
|
||||||
|
|
||||||
// Unmarshal the raw JSON data in a "raw" JSON map.
|
// Convert raw bytes to an AP type.
|
||||||
if err := json.Unmarshal(b, &raw); err != nil {
|
// This will also populate the map.
|
||||||
return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err)
|
t, err := bytesToType(ctx, b, raw)
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve an ActivityStreams type from JSON.
|
|
||||||
t, err := streams.ToType(ctx, raw)
|
|
||||||
if err != nil {
|
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.
|
// Attempt to cast as Statusable.
|
||||||
|
@ -166,15 +192,11 @@ func ResolveAccountable(ctx context.Context, b []byte) (Accountable, error) {
|
||||||
// destination.
|
// destination.
|
||||||
raw := getMap()
|
raw := getMap()
|
||||||
|
|
||||||
// Unmarshal the raw JSON data in a "raw" JSON map.
|
// Convert raw bytes to an AP type.
|
||||||
if err := json.Unmarshal(b, &raw); err != nil {
|
// This will also populate the map.
|
||||||
return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err)
|
t, err := bytesToType(ctx, b, raw)
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve an ActivityStreams type from JSON.
|
|
||||||
t, err := streams.ToType(ctx, raw)
|
|
||||||
if err != nil {
|
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.
|
// Attempt to cast as Statusable.
|
||||||
|
|
|
@ -47,6 +47,29 @@ func (suite *ResolveTestSuite) TestResolveDocumentAsAccountable() {
|
||||||
suite.Nil(accountable)
|
suite.Nil(accountable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ResolveTestSuite) TestResolveHTMLAsAccountable() {
|
||||||
|
b := []byte(`<!DOCTYPE html>
|
||||||
|
<title>.</title>`)
|
||||||
|
|
||||||
|
accountable, err := ap.ResolveAccountable(context.Background(), b)
|
||||||
|
suite.True(gtserror.IsWrongType(err))
|
||||||
|
suite.EqualError(err, "ResolveAccountable: error unmarshalling bytes into json: invalid character '<' looking for beginning of value")
|
||||||
|
suite.Nil(accountable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ResolveTestSuite) TestResolveNonAPJSONAsAccountable() {
|
||||||
|
b := []byte(`{
|
||||||
|
"@context": "definitely a legit context muy lord",
|
||||||
|
"type": "definitely an account muy lord",
|
||||||
|
"pee pee":"poo poo"
|
||||||
|
}`)
|
||||||
|
|
||||||
|
accountable, err := ap.ResolveAccountable(context.Background(), b)
|
||||||
|
suite.True(gtserror.IsWrongType(err))
|
||||||
|
suite.EqualError(err, "ResolveAccountable: error resolving json into ap vocab type: activity stream did not match any known types")
|
||||||
|
suite.Nil(accountable)
|
||||||
|
}
|
||||||
|
|
||||||
func TestResolveTestSuite(t *testing.T) {
|
func TestResolveTestSuite(t *testing.T) {
|
||||||
suite.Run(t, &ResolveTestSuite{})
|
suite.Run(t, &ResolveTestSuite{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,15 @@ func SetUnretrievable(err error) error {
|
||||||
return errors.WithValue(err, unrtrvableKey, struct{}{})
|
return errors.WithValue(err, unrtrvableKey, struct{}{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWrongType checks error for a stored "wrong type" flag. Wrong type
|
// IsWrongType checks error for a stored "wrong type" flag.
|
||||||
// indicates that an ActivityPub URI returned a type we weren't expecting:
|
// Wrong type indicates that an ActivityPub URI returned a
|
||||||
// Statusable instead of Accountable, or vice versa, for example.
|
// type we weren't expecting. For example:
|
||||||
|
//
|
||||||
|
// - HTML instead of JSON.
|
||||||
|
// - Normal JSON instead of ActivityPub JSON.
|
||||||
|
// - Statusable instead of Accountable.
|
||||||
|
// - Accountable instead of Statusable.
|
||||||
|
// - etc.
|
||||||
func IsWrongType(err error) bool {
|
func IsWrongType(err error) bool {
|
||||||
_, ok := errors.Value(err, wrongTypeKey).(struct{})
|
_, ok := errors.Value(err, wrongTypeKey).(struct{})
|
||||||
return ok
|
return ok
|
||||||
|
|
Loading…
Reference in New Issue