Handle forwarded messages (#273)

* correct path of foss_satan

* add APIri and notes

* test create forward note

* rename target => receiving account

* split up create into separate funcs

* update extractFromCtx

* tidy up from federator processing

* foss satan => http not https

* check if status in db

* mock dereference of status from IRI

* add forward message deref test

* update test with activities

* add remote_account_2 to test rig
This commit is contained in:
tobi 2021-10-10 12:39:25 +02:00 committed by GitHub
commit 367bdca250
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 765 additions and 383 deletions

View file

@ -48,12 +48,9 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
l.Debug("entering Accept")
}
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, _, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
@ -77,7 +74,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
}
// make sure the addressee of the original follow is the same as whatever inbox this landed in
if gtsFollowRequest.AccountID != targetAcct.ID {
if gtsFollowRequest.AccountID != receivingAccount.ID {
return errors.New("ACCEPT: follow object account and inbox account were not the same")
}
follow, err := f.db.AcceptFollowRequest(ctx, gtsFollowRequest.AccountID, gtsFollowRequest.TargetAccountID)
@ -89,7 +86,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
APObjectType: ap.ActivityFollow,
APActivityType: ap.ActivityAccept,
GTSModel: follow,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
return nil
@ -114,7 +111,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
return fmt.Errorf("ACCEPT: error converting asfollow to gtsfollow: %s", err)
}
// make sure the addressee of the original follow is the same as whatever inbox this landed in
if gtsFollow.AccountID != targetAcct.ID {
if gtsFollow.AccountID != receivingAccount.ID {
return errors.New("ACCEPT: follow object account and inbox account were not the same")
}
follow, err := f.db.AcceptFollowRequest(ctx, gtsFollow.AccountID, gtsFollow.TargetAccountID)
@ -126,7 +123,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
APObjectType: ap.ActivityFollow,
APActivityType: ap.ActivityAccept,
GTSModel: follow,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
return nil

View file

@ -44,12 +44,9 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
l.Debug("entering Announce")
}
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, _, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
@ -57,7 +54,7 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
boost, isNew, err := f.typeConverter.ASAnnounceToStatus(ctx, announce)
if err != nil {
return fmt.Errorf("ANNOUNCE: error converting announce to boost: %s", err)
return fmt.Errorf("Announce: error converting announce to boost: %s", err)
}
if !isNew {
@ -70,7 +67,7 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
APObjectType: ap.ActivityAnnounce,
APActivityType: ap.ActivityCreate,
GTSModel: boost,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
return nil

View file

@ -22,11 +22,13 @@ import (
"context"
"errors"
"fmt"
"strings"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/id"
"github.com/superseriousbusiness/gotosocial/internal/messages"
)
@ -59,144 +61,261 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
l.Debug("entering Create")
}
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, requestingAccount, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
}
switch asType.GetTypeName() {
case ap.ActivityCreate:
// CREATE SOMETHING
create, ok := asType.(vocab.ActivityStreamsCreate)
if !ok {
return errors.New("CREATE: could not convert type to create")
}
object := create.GetActivityStreamsObject()
for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {
switch objectIter.GetType().GetTypeName() {
case ap.ObjectNote:
// CREATE A NOTE
note := objectIter.GetActivityStreamsNote()
status, err := f.typeConverter.ASStatusToStatus(ctx, note)
if err != nil {
return fmt.Errorf("CREATE: error converting note to status: %s", err)
}
// id the status based on the time it was created
statusID, err := id.NewULIDFromTime(status.CreatedAt)
if err != nil {
return err
}
status.ID = statusID
if err := f.db.PutStatus(ctx, status); err != nil {
if err == db.ErrAlreadyExists {
// the status already exists in the database, which means we've already handled everything else,
// so we can just return nil here and be done with it.
return nil
}
// an actual error has happened
return fmt.Errorf("CREATE: database error inserting status: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ObjectNote,
APActivityType: ap.ActivityCreate,
GTSModel: status,
ReceivingAccount: targetAcct,
}
}
}
case ap.ActivityFollow:
// FOLLOW SOMETHING
follow, ok := asType.(vocab.ActivityStreamsFollow)
if !ok {
return errors.New("CREATE: could not convert type to follow")
}
followRequest, err := f.typeConverter.ASFollowToFollowRequest(ctx, follow)
if err != nil {
return fmt.Errorf("CREATE: could not convert Follow to follow request: %s", err)
}
newID, err := id.NewULID()
if err != nil {
return err
}
followRequest.ID = newID
if err := f.db.Put(ctx, followRequest); err != nil {
return fmt.Errorf("CREATE: database error inserting follow request: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityFollow,
APActivityType: ap.ActivityCreate,
GTSModel: followRequest,
ReceivingAccount: targetAcct,
}
case ap.ActivityLike:
// LIKE SOMETHING
like, ok := asType.(vocab.ActivityStreamsLike)
if !ok {
return errors.New("CREATE: could not convert type to like")
}
fave, err := f.typeConverter.ASLikeToFave(ctx, like)
if err != nil {
return fmt.Errorf("CREATE: could not convert Like to fave: %s", err)
}
newID, err := id.NewULID()
if err != nil {
return err
}
fave.ID = newID
if err := f.db.Put(ctx, fave); err != nil {
return fmt.Errorf("CREATE: database error inserting fave: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityLike,
APActivityType: ap.ActivityCreate,
GTSModel: fave,
ReceivingAccount: targetAcct,
}
case ap.ActivityBlock:
// BLOCK SOMETHING
blockable, ok := asType.(vocab.ActivityStreamsBlock)
if !ok {
return errors.New("CREATE: could not convert type to block")
}
block, err := f.typeConverter.ASBlockToBlock(ctx, blockable)
if err != nil {
return fmt.Errorf("CREATE: could not convert Block to gts model block")
}
newID, err := id.NewULID()
if err != nil {
return err
}
block.ID = newID
if err := f.db.Put(ctx, block); err != nil {
return fmt.Errorf("CREATE: database error inserting block: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityBlock,
APActivityType: ap.ActivityCreate,
GTSModel: block,
ReceivingAccount: targetAcct,
}
return f.activityBlock(ctx, asType, receivingAccount, requestingAccount, fromFederatorChan)
case ap.ActivityCreate:
// CREATE SOMETHING
return f.activityCreate(ctx, asType, receivingAccount, requestingAccount, fromFederatorChan)
case ap.ActivityFollow:
// FOLLOW SOMETHING
return f.activityFollow(ctx, asType, receivingAccount, requestingAccount, fromFederatorChan)
case ap.ActivityLike:
// LIKE SOMETHING
return f.activityLike(ctx, asType, receivingAccount, requestingAccount, fromFederatorChan)
}
return nil
}
/*
BLOCK HANDLERS
*/
func (f *federatingDB) activityBlock(ctx context.Context, asType vocab.Type, receiving *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) error {
blockable, ok := asType.(vocab.ActivityStreamsBlock)
if !ok {
return errors.New("activityBlock: could not convert type to block")
}
block, err := f.typeConverter.ASBlockToBlock(ctx, blockable)
if err != nil {
return fmt.Errorf("activityBlock: could not convert Block to gts model block")
}
newID, err := id.NewULID()
if err != nil {
return err
}
block.ID = newID
if err := f.db.Put(ctx, block); err != nil {
return fmt.Errorf("activityBlock: database error inserting block: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityBlock,
APActivityType: ap.ActivityCreate,
GTSModel: block,
ReceivingAccount: receiving,
}
return nil
}
/*
CREATE HANDLERS
*/
func (f *federatingDB) activityCreate(ctx context.Context, asType vocab.Type, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) error {
create, ok := asType.(vocab.ActivityStreamsCreate)
if !ok {
return errors.New("activityCreate: could not convert type to create")
}
// create should have an object
object := create.GetActivityStreamsObject()
if object == nil {
return errors.New("Create had no Object")
}
errs := []string{}
// iterate through the object(s) to see what we're meant to be creating
for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {
asObjectType := objectIter.GetType()
if asObjectType == nil {
// currently we can't do anything with just a Create of something that's not an Object with a type
// TODO: process a Create with an Object that's just a URI or something
errs = append(errs, "object of Create was not a Type")
continue
}
// we have a type -- what is it?
asObjectTypeName := asObjectType.GetTypeName()
switch asObjectTypeName {
case ap.ObjectNote:
// CREATE A NOTE
if err := f.createNote(ctx, objectIter.GetActivityStreamsNote(), receivingAccount, requestingAccount, fromFederatorChan); err != nil {
errs = append(errs, err.Error())
}
default:
errs = append(errs, fmt.Sprintf("received an object on a Create that we couldn't handle: %s", asObjectType.GetTypeName()))
}
}
if len(errs) != 0 {
return fmt.Errorf("activityCreate: one or more errors while processing activity: %s", strings.Join(errs, "; "))
}
return nil
}
// createNote handles a Create activity with a Note type.
func (f *federatingDB) createNote(ctx context.Context, note vocab.ActivityStreamsNote, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) error {
l := f.log.WithFields(logrus.Fields{
"func": "createNote",
"receivingAccount": receivingAccount.URI,
"requestingAccount": requestingAccount.URI,
})
// Check if we have a forward.
// In other words, was the note posted to our inbox by at least one actor who actually created the note, or are they just forwarding it?
forward := true
// note should have an attributedTo
noteAttributedTo := note.GetActivityStreamsAttributedTo()
if noteAttributedTo == nil {
return errors.New("createNote: note had no attributedTo")
}
// compare the attributedTo(s) with the actor who posted this to our inbox
for attributedToIter := noteAttributedTo.Begin(); attributedToIter != noteAttributedTo.End(); attributedToIter = attributedToIter.Next() {
if !attributedToIter.IsIRI() {
continue
}
iri := attributedToIter.GetIRI()
if requestingAccount.URI == iri.String() {
// at least one creator of the note, and the actor who posted the note to our inbox, are the same, so it's not a forward
forward = false
}
}
// If we do have a forward, we should ignore the content for now and just dereference based on the URL/ID of the note instead, to get the note straight from the horse's mouth
if forward {
l.Trace("note is a forward")
id := note.GetJSONLDId()
if !id.IsIRI() {
// if the note id isn't an IRI, there's nothing we can do here
return nil
}
// pass the note iri into the processor and have it do the dereferencing instead of doing it here
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ObjectNote,
APActivityType: ap.ActivityCreate,
APIri: id.GetIRI(),
GTSModel: nil,
ReceivingAccount: receivingAccount,
}
return nil
}
// if we reach this point, we know it's not a forwarded status, so proceed with processing it as normal
status, err := f.typeConverter.ASStatusToStatus(ctx, note)
if err != nil {
return fmt.Errorf("createNote: error converting note to status: %s", err)
}
// id the status based on the time it was created
statusID, err := id.NewULIDFromTime(status.CreatedAt)
if err != nil {
return err
}
status.ID = statusID
if err := f.db.PutStatus(ctx, status); err != nil {
if err == db.ErrAlreadyExists {
// the status already exists in the database, which means we've already handled everything else,
// so we can just return nil here and be done with it.
return nil
}
// an actual error has happened
return fmt.Errorf("createNote: database error inserting status: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ObjectNote,
APActivityType: ap.ActivityCreate,
GTSModel: status,
ReceivingAccount: receivingAccount,
}
return nil
}
/*
FOLLOW HANDLERS
*/
func (f *federatingDB) activityFollow(ctx context.Context, asType vocab.Type, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) error {
follow, ok := asType.(vocab.ActivityStreamsFollow)
if !ok {
return errors.New("activityFollow: could not convert type to follow")
}
followRequest, err := f.typeConverter.ASFollowToFollowRequest(ctx, follow)
if err != nil {
return fmt.Errorf("activityFollow: could not convert Follow to follow request: %s", err)
}
newID, err := id.NewULID()
if err != nil {
return err
}
followRequest.ID = newID
if err := f.db.Put(ctx, followRequest); err != nil {
return fmt.Errorf("activityFollow: database error inserting follow request: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityFollow,
APActivityType: ap.ActivityCreate,
GTSModel: followRequest,
ReceivingAccount: receivingAccount,
}
return nil
}
/*
LIKE HANDLERS
*/
func (f *federatingDB) activityLike(ctx context.Context, asType vocab.Type, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) error {
like, ok := asType.(vocab.ActivityStreamsLike)
if !ok {
return errors.New("activityLike: could not convert type to like")
}
fave, err := f.typeConverter.ASLikeToFave(ctx, like)
if err != nil {
return fmt.Errorf("activityLike: could not convert Like to fave: %s", err)
}
newID, err := id.NewULID()
if err != nil {
return err
}
fave.ID = newID
if err := f.db.Put(ctx, fave); err != nil {
return fmt.Errorf("activityLike: database error inserting fave: %s", err)
}
fromFederatorChan <- messages.FromFederator{
APObjectType: ap.ActivityLike,
APActivityType: ap.ActivityCreate,
GTSModel: fave,
ReceivingAccount: receivingAccount,
}
return nil
}

View file

@ -0,0 +1,91 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package federatingdb_test
import (
"context"
"testing"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/messages"
)
type CreateTestSuite struct {
FederatingDBTestSuite
}
func (suite *CreateTestSuite) TestCreateNote() {
receivingAccount := suite.testAccounts["local_account_1"]
requestingAccount := suite.testAccounts["remote_account_1"]
fromFederatorChan := make(chan messages.FromFederator, 10)
ctx := createTestContext(receivingAccount, requestingAccount, fromFederatorChan)
create := suite.testActivities["dm_for_zork"].Activity
err := suite.federatingDB.Create(ctx, create)
suite.NoError(err)
// should be a message heading to the processor now, which we can intercept here
msg := <-fromFederatorChan
suite.Equal(ap.ObjectNote, msg.APObjectType)
suite.Equal(ap.ActivityCreate, msg.APActivityType)
// shiny new status should be defined on the message
suite.NotNil(msg.GTSModel)
status := msg.GTSModel.(*gtsmodel.Status)
// status should have some expected values
suite.Equal(requestingAccount.ID, status.AccountID)
suite.Equal("hey zork here's a new private note for you", status.Content)
// status should be in the database
_, err = suite.db.GetStatusByID(context.Background(), status.ID)
suite.NoError(err)
}
func (suite *CreateTestSuite) TestCreateNoteForward() {
receivingAccount := suite.testAccounts["local_account_1"]
requestingAccount := suite.testAccounts["remote_account_1"]
fromFederatorChan := make(chan messages.FromFederator, 10)
ctx := createTestContext(receivingAccount, requestingAccount, fromFederatorChan)
create := suite.testActivities["forwarded_message"].Activity
err := suite.federatingDB.Create(ctx, create)
suite.NoError(err)
// should be a message heading to the processor now, which we can intercept here
msg := <-fromFederatorChan
suite.Equal(ap.ObjectNote, msg.APObjectType)
suite.Equal(ap.ActivityCreate, msg.APActivityType)
// nothing should be set as the model since this is a forward
suite.Nil(msg.GTSModel)
// but we should have a uri set
suite.Equal("http://example.org/users/some_user/statuses/afaba698-5740-4e32-a702-af61aa543bc1", msg.APIri.String())
}
func TestCreateTestSuite(t *testing.T) {
suite.Run(t, &CreateTestSuite{})
}

View file

@ -44,12 +44,9 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
)
l.Debug("entering Delete")
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, _, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
@ -68,7 +65,7 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
APObjectType: ap.ObjectNote,
APActivityType: ap.ActivityDelete,
GTSModel: s,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
}
@ -80,7 +77,7 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
APObjectType: ap.ObjectProfile,
APActivityType: ap.ActivityDelete,
GTSModel: a,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
}

View file

@ -19,13 +19,17 @@
package federatingdb_test
import (
"context"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/federation/federatingdb"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
"github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@ -45,6 +49,7 @@ type FederatingDBTestSuite struct {
testAttachments map[string]*gtsmodel.MediaAttachment
testStatuses map[string]*gtsmodel.Status
testBlocks map[string]*gtsmodel.Block
testActivities map[string]testrig.ActivityWithSignature
}
func (suite *FederatingDBTestSuite) SetupSuite() {
@ -56,6 +61,7 @@ func (suite *FederatingDBTestSuite) SetupSuite() {
suite.testAttachments = testrig.NewTestAttachments()
suite.testStatuses = testrig.NewTestStatuses()
suite.testBlocks = testrig.NewTestBlocks()
suite.testActivities = testrig.NewTestActivities(suite.testAccounts)
}
func (suite *FederatingDBTestSuite) SetupTest() {
@ -70,3 +76,11 @@ func (suite *FederatingDBTestSuite) SetupTest() {
func (suite *FederatingDBTestSuite) TearDownTest() {
testrig.StandardDBTeardown(suite.db)
}
func createTestContext(receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) context.Context {
ctx := context.Background()
ctx = context.WithValue(ctx, util.APReceivingAccount, receivingAccount)
ctx = context.WithValue(ctx, util.APRequestingAccount, requestingAccount)
ctx = context.WithValue(ctx, util.APFromFederatorChanKey, fromFederatorChan)
return ctx
}

View file

@ -46,12 +46,9 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
l.Debug("entering Undo")
}
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, _, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
@ -83,7 +80,7 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
return fmt.Errorf("UNDO: error converting asfollow to gtsfollow: %s", err)
}
// make sure the addressee of the original follow is the same as whatever inbox this landed in
if gtsFollow.TargetAccountID != targetAcct.ID {
if gtsFollow.TargetAccountID != receivingAccount.ID {
return errors.New("UNDO: follow object account and inbox account were not the same")
}
// delete any existing FOLLOW
@ -116,7 +113,7 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
return fmt.Errorf("UNDO: error converting asblock to gtsblock: %s", err)
}
// make sure the addressee of the original block is the same as whatever inbox this landed in
if gtsBlock.TargetAccountID != targetAcct.ID {
if gtsBlock.TargetAccountID != receivingAccount.ID {
return errors.New("UNDO: block object account and inbox account were not the same")
}
// delete any existing BLOCK

View file

@ -56,12 +56,9 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l.Debug("entering Update")
}
targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
if targetAcct == nil || fromFederatorChan == nil {
// If the target account or federator channel wasn't set on the context, that means this request didn't pass
receivingAccount, _, fromFederatorChan := extractFromCtx(ctx)
if receivingAccount == nil || fromFederatorChan == nil {
// If the receiving account or federator channel wasn't set on the context, that means this request didn't pass
// through the API, but came from inside GtS as the result of another activity on this instance. That being so,
// we can safely just ignore this activity, since we know we've already processed it elsewhere.
return nil
@ -153,7 +150,7 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
APObjectType: ap.ObjectProfile,
APActivityType: ap.ActivityUpdate,
GTSModel: updatedAcct,
ReceivingAccount: targetAcct,
ReceivingAccount: receivingAccount,
}
}

View file

@ -289,29 +289,26 @@ func (f *federatingDB) collectIRIs(ctx context.Context, iris []*url.URL) (vocab.
// extractFromCtx extracts some useful values from a context passed into the federatingDB via the API:
// - The target account that owns the inbox or URI being interacted with.
// - The requesting account that posted to the inbox.
// - A channel that messages for the processor can be placed into.
func extractFromCtx(ctx context.Context) (*gtsmodel.Account, chan messages.FromFederator, error) {
var targetAcct *gtsmodel.Account
targetAcctI := ctx.Value(util.APAccount)
if targetAcctI != nil {
var ok bool
targetAcct, ok = targetAcctI.(*gtsmodel.Account)
if !ok {
return nil, nil, errors.New("extractFromCtx: account value in context not parseable")
}
// If a value is not present, nil will be returned for it. It's up to the caller to check this and respond appropriately.
func extractFromCtx(ctx context.Context) (receivingAccount, requestingAccount *gtsmodel.Account, fromFederatorChan chan messages.FromFederator) {
receivingAccountI := ctx.Value(util.APReceivingAccount)
if receivingAccountI != nil {
receivingAccount = receivingAccountI.(*gtsmodel.Account)
}
requestingAcctI := ctx.Value(util.APRequestingAccount)
if requestingAcctI != nil {
requestingAccount = requestingAcctI.(*gtsmodel.Account)
}
var fromFederatorChan chan messages.FromFederator
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
if fromFederatorChanI != nil {
var ok bool
fromFederatorChan, ok = fromFederatorChanI.(chan messages.FromFederator)
if !ok {
return nil, nil, errors.New("extractFromCtx: fromFederatorChan value in context not parseable")
}
fromFederatorChan = fromFederatorChanI.(chan messages.FromFederator)
}
return targetAcct, fromFederatorChan, nil
return
}
func marshalItem(item vocab.Type) (string, error) {