Add tests for PostInbox Object/Target requirements
Also fixed my earlier stupidity at requiring a 'type' when I meant to require a 'target'. Also added the missing checks to the federated handlers.
このコミットが含まれているのは:
コミット
7d049ea3d4
53
pub/fed.go
53
pub/fed.go
|
@ -15,8 +15,8 @@ import (
|
|||
var (
|
||||
// ErrObjectRequired means the activity needs its object property set.
|
||||
ErrObjectRequired = errors.New("object property required")
|
||||
// ErrTypeRequired means the activity needs its type property set.
|
||||
ErrTypeRequired = errors.New("type property required")
|
||||
// ErrTargetRequired means the activity needs its target property set.
|
||||
ErrTargetRequired = errors.New("target property required")
|
||||
)
|
||||
|
||||
// TODO: Helper http Handler for serving ActivityStream objects
|
||||
|
@ -43,7 +43,7 @@ type Pubber interface {
|
|||
// the request as an ActivityPub request. If it returns an error, it is up to
|
||||
// the client to determine how to respond via HTTP.
|
||||
//
|
||||
// Note that the error could be ErrObjectRequired or ErrTypeRequired.
|
||||
// Note that the error could be ErrObjectRequired or ErrTargetRequired.
|
||||
PostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
|
||||
GetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
|
||||
}
|
||||
|
@ -559,8 +559,8 @@ func (f *federator) handleClientAdd(c context.Context, deliverable *bool) func(s
|
|||
*deliverable = true
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
} else if s.LenType() == 0 {
|
||||
return ErrTypeRequired
|
||||
} else if s.LenTarget() == 0 {
|
||||
return ErrTargetRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
ids, err := getTargetIds(raw)
|
||||
|
@ -623,8 +623,8 @@ func (f *federator) handleClientRemove(c context.Context, deliverable *bool) fun
|
|||
*deliverable = true
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
} else if s.LenType() == 0 {
|
||||
return ErrTypeRequired
|
||||
} else if s.LenTarget() == 0 {
|
||||
return ErrTargetRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
ids, err := getTargetIds(raw)
|
||||
|
@ -750,6 +750,7 @@ func (f *federator) getPostInboxResolver(c context.Context) *streams.Resolver {
|
|||
RemoveCallback: f.handleRemove(c),
|
||||
LikeCallback: f.handleLike(c),
|
||||
UndoCallback: f.handleUndo(c),
|
||||
BlockCallback: f.handleBlock(c),
|
||||
// TODO: Extended activity types, such as Announce, Arrive, etc.
|
||||
}
|
||||
}
|
||||
|
@ -758,6 +759,9 @@ func (f *federator) handleCreate(c context.Context) func(s *streams.Create) erro
|
|||
return func(s *streams.Create) error {
|
||||
// Create requires the client application to persist the 'object' that
|
||||
// was created.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
for i := 0; i < raw.ObjectLen(); i++ {
|
||||
if !raw.IsObject(i) {
|
||||
|
@ -777,6 +781,9 @@ func (f *federator) handleUpdate(c context.Context) func(s *streams.Update) erro
|
|||
return func(s *streams.Update) error {
|
||||
// TODO: The receiving server MUST take care to be sure that the Update
|
||||
// is authorized to modify its object.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
for i := 0; i < raw.ObjectLen(); i++ {
|
||||
if !raw.IsObject(i) {
|
||||
|
@ -796,6 +803,9 @@ func (f *federator) handleDelete(c context.Context) func(s *streams.Delete) erro
|
|||
return func(s *streams.Delete) error {
|
||||
// TODO: Verify ownership. I think the spec unintentionally suggests to
|
||||
// just assume it is owned, so we will actually verify.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
ids, err := getObjectIds(s.Raw())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -824,6 +834,9 @@ func (f *federator) handleFollow(c context.Context) func(s *streams.Follow) erro
|
|||
return func(s *streams.Follow) error {
|
||||
// Permit either human-triggered or automatically triggering
|
||||
// 'Accept'/'Reject'.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
todo := f.FederateApp.OnFollow(c, s)
|
||||
if todo != DoNothing {
|
||||
var activity vocab.ActivityType
|
||||
|
@ -940,8 +953,8 @@ func (f *federator) handleAdd(c context.Context) func(s *streams.Add) error {
|
|||
// 'object' to a specific 'target' collection.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
} else if s.LenType() == 0 {
|
||||
return ErrTypeRequired
|
||||
} else if s.LenTarget() == 0 {
|
||||
return ErrTargetRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
ids, err := getTargetIds(raw)
|
||||
|
@ -1005,8 +1018,8 @@ func (f *federator) handleRemove(c context.Context) func(s *streams.Remove) erro
|
|||
// an 'object' from a specific 'target' collection.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
} else if s.LenType() == 0 {
|
||||
return ErrTypeRequired
|
||||
} else if s.LenTarget() == 0 {
|
||||
return ErrTargetRequired
|
||||
}
|
||||
raw := s.Raw()
|
||||
ids, err := getTargetIds(raw)
|
||||
|
@ -1066,6 +1079,9 @@ func (f *federator) handleRemove(c context.Context) func(s *streams.Remove) erro
|
|||
|
||||
func (f *federator) handleLike(c context.Context) func(s *streams.Like) error {
|
||||
return func(s *streams.Like) error {
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
getter := func(object vocab.ObjectType, lc *vocab.CollectionType, loc *vocab.OrderedCollectionType) error {
|
||||
if object.IsLikesAnyURI() {
|
||||
pObj, err := f.App.Get(c, object.GetLikesAnyURI())
|
||||
|
@ -1102,6 +1118,21 @@ func (f *federator) handleUndo(c context.Context) func(s *streams.Undo) error {
|
|||
// application is responsible for enforcing this. Note that 'Undo'-ing
|
||||
// is not a deletion of a previous Activity, but the addition of its
|
||||
// opposite.
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
return f.ServerCallbacker.Undo(c, s)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *federator) handleBlock(c context.Context) func(s *streams.Block) error {
|
||||
// Servers SHOULD NOT deliver Block Activities to their object. So in
|
||||
// this case we will explicitly ignore it, but validate it as if we
|
||||
// were to accept it.
|
||||
return func(s *streams.Block) error {
|
||||
if s.LenObject() == 0 {
|
||||
return ErrObjectRequired
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
182
pub/fed_test.go
182
pub/fed_test.go
|
@ -1112,6 +1112,166 @@ func TestPostInbox_HandlesBlocked(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPostInbox_RequiresObject(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input func() vocab.Serializer
|
||||
}{
|
||||
{
|
||||
name: "create",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Create{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddSummaryString("Sally created a note")
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Update{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddSummaryString("Sally updated a note")
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Delete{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "follow",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Follow{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Add{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
v.AddTargetObject(testNote)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Remove{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
v.AddTargetObject(testNote)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "like",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Like{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "block",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Block{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undo",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Undo{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
return v
|
||||
},
|
||||
},
|
||||
}
|
||||
_, _, fedApp, _, _, _, _, p := NewPubberTest(t)
|
||||
fedApp.unblocked = func(c context.Context, actorIRIs []url.URL) error {
|
||||
return nil
|
||||
}
|
||||
for _, test := range tests {
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input()))))
|
||||
handled, err := p.PostInbox(context.Background(), resp, req)
|
||||
if err != ErrObjectRequired {
|
||||
t.Fatalf("(%s) expected %s, got %s", test.name, ErrObjectRequired, err)
|
||||
} else if !handled {
|
||||
t.Fatalf("(%s) expected handled, got !handled", test.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostInbox_RequiresTarget(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input func() vocab.Serializer
|
||||
}{
|
||||
{
|
||||
name: "add",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Add{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
v.AddObject(testNote)
|
||||
return v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove",
|
||||
input: func() vocab.Serializer {
|
||||
v := &vocab.Remove{}
|
||||
v.SetId(*noteActivityIRI)
|
||||
v.AddActorObject(sallyActor)
|
||||
v.AddToObject(samActor)
|
||||
v.AddObject(testNote)
|
||||
return v
|
||||
},
|
||||
},
|
||||
}
|
||||
_, _, fedApp, _, _, _, _, p := NewPubberTest(t)
|
||||
fedApp.unblocked = func(c context.Context, actorIRIs []url.URL) error {
|
||||
return nil
|
||||
}
|
||||
for _, test := range tests {
|
||||
resp := httptest.NewRecorder()
|
||||
req := ActivityPubRequest(httptest.NewRequest("POST", testInboxURI, bytes.NewBuffer(MustSerialize(test.input()))))
|
||||
handled, err := p.PostInbox(context.Background(), resp, req)
|
||||
if err != ErrTargetRequired {
|
||||
t.Fatalf("(%s) expected %s, got %s", test.name, ErrTargetRequired, err)
|
||||
} else if !handled {
|
||||
t.Fatalf("(%s) expected handled, got !handled", test.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostInbox_Create_SetsObject(t *testing.T) {
|
||||
app, _, fedApp, _, fedCb, _, _, p := NewPubberTest(t)
|
||||
resp := httptest.NewRecorder()
|
||||
|
@ -1831,14 +1991,6 @@ func TestPostInbox_Reject_CallsCallback(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPostInbox_Add_RequireObject(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostInbox_Add_RequireType(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostInbox_Add_DoesNotAddIfTargetNotOwned(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
@ -1863,14 +2015,6 @@ func TestPostInbox_Add_CallsCallback(t *testing.T) {
|
|||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostInbox_Remove_RequireObject(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostInbox_Remove_RequireType(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostInbox_Remove_DoesNotAddIfTargetNotOwned(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
@ -2023,7 +2167,7 @@ func TestPostOutbox_Add_RequireObject(t *testing.T) {
|
|||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostOutbox_Add_RequireType(t *testing.T) {
|
||||
func TestPostOutbox_Add_RequireTarget(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
|
@ -2059,7 +2203,7 @@ func TestPostOutbox_Remove_RequireObject(t *testing.T) {
|
|||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostOutbox_Remove_RequireType(t *testing.T) {
|
||||
func TestPostOutbox_Remove_RequireTarget(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
|
@ -2095,7 +2239,7 @@ func TestPostOutbox_Like_RequireObject(t *testing.T) {
|
|||
// TODO: Implement
|
||||
}
|
||||
|
||||
func TestPostOutbox_Like_RequireType(t *testing.T) {
|
||||
func TestPostOutbox_Like_RequireTarget(t *testing.T) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
|
|
読み込み中…
新しいイシューから参照