summaryrefslogtreecommitdiff
path: root/internal/federation
diff options
context:
space:
mode:
Diffstat (limited to 'internal/federation')
-rw-r--r--internal/federation/authenticate.go4
-rw-r--r--internal/federation/dereferencing/account.go4
-rw-r--r--internal/federation/dereferencing/collectionpage.go4
-rw-r--r--internal/federation/dereferencing/instance.go2
-rw-r--r--internal/federation/dereferencing/status.go4
-rw-r--r--internal/federation/federatingdb/accept.go44
-rw-r--r--internal/federation/federatingdb/announce.go44
-rw-r--r--internal/federation/federatingdb/create.go47
-rw-r--r--internal/federation/federatingdb/delete.go32
-rw-r--r--internal/federation/federatingdb/exists.go7
-rw-r--r--internal/federation/federatingdb/federatingdb_test.go53
-rw-r--r--internal/federation/federatingdb/followers.go47
-rw-r--r--internal/federation/federatingdb/followers_test.go53
-rw-r--r--internal/federation/federatingdb/following.go63
-rw-r--r--internal/federation/federatingdb/following_test.go53
-rw-r--r--internal/federation/federatingdb/get.go33
-rw-r--r--internal/federation/federatingdb/inbox.go45
-rw-r--r--internal/federation/federatingdb/liked.go13
-rw-r--r--internal/federation/federatingdb/outbox.go43
-rw-r--r--internal/federation/federatingdb/owns.go4
-rw-r--r--internal/federation/federatingdb/undo.go34
-rw-r--r--internal/federation/federatingdb/update.go44
-rw-r--r--internal/federation/federatingdb/util.go163
-rw-r--r--internal/federation/finger.go2
24 files changed, 433 insertions, 409 deletions
diff --git a/internal/federation/authenticate.go b/internal/federation/authenticate.go
index 1e359aa28..da5d2b93d 100644
--- a/internal/federation/authenticate.go
+++ b/internal/federation/authenticate.go
@@ -185,13 +185,13 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
}
// The actual http call to the remote server is made right here in the Dereference function.
- b, err := transport.Dereference(context.Background(), requestingPublicKeyID)
+ b, err := transport.Dereference(ctx, requestingPublicKeyID)
if err != nil {
return nil, false, fmt.Errorf("error deferencing key %s: %s", requestingPublicKeyID.String(), err)
}
// if the key isn't in the response, we can't authenticate the request
- requestingPublicKey, err := getPublicKeyFromResponse(context.Background(), b, requestingPublicKeyID)
+ requestingPublicKey, err := getPublicKeyFromResponse(ctx, b, requestingPublicKeyID)
if err != nil {
return nil, false, fmt.Errorf("error getting key %s from response %s: %s", requestingPublicKeyID.String(), string(b), err)
}
diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go
index 35ea2507d..6acb3b06d 100644
--- a/internal/federation/dereferencing/account.go
+++ b/internal/federation/dereferencing/account.go
@@ -149,7 +149,7 @@ func (d *deref) dereferenceAccountable(ctx context.Context, username string, rem
return nil, fmt.Errorf("DereferenceAccountable: transport err: %s", err)
}
- b, err := transport.Dereference(context.Background(), remoteAccountID)
+ b, err := transport.Dereference(ctx, remoteAccountID)
if err != nil {
return nil, fmt.Errorf("DereferenceAccountable: error deferencing %s: %s", remoteAccountID.String(), err)
}
@@ -159,7 +159,7 @@ func (d *deref) dereferenceAccountable(ctx context.Context, username string, rem
return nil, fmt.Errorf("DereferenceAccountable: error unmarshalling bytes into json: %s", err)
}
- t, err := streams.ToType(context.Background(), m)
+ t, err := streams.ToType(ctx, m)
if err != nil {
return nil, fmt.Errorf("DereferenceAccountable: error resolving json into ap vocab type: %s", err)
}
diff --git a/internal/federation/dereferencing/collectionpage.go b/internal/federation/dereferencing/collectionpage.go
index c5a54402c..cf97327a5 100644
--- a/internal/federation/dereferencing/collectionpage.go
+++ b/internal/federation/dereferencing/collectionpage.go
@@ -41,7 +41,7 @@ func (d *deref) DereferenceCollectionPage(ctx context.Context, username string,
return nil, fmt.Errorf("DereferenceCollectionPage: error creating transport: %s", err)
}
- b, err := transport.Dereference(context.Background(), pageIRI)
+ b, err := transport.Dereference(ctx, pageIRI)
if err != nil {
return nil, fmt.Errorf("DereferenceCollectionPage: error deferencing %s: %s", pageIRI.String(), err)
}
@@ -51,7 +51,7 @@ func (d *deref) DereferenceCollectionPage(ctx context.Context, username string,
return nil, fmt.Errorf("DereferenceCollectionPage: error unmarshalling bytes into json: %s", err)
}
- t, err := streams.ToType(context.Background(), m)
+ t, err := streams.ToType(ctx, m)
if err != nil {
return nil, fmt.Errorf("DereferenceCollectionPage: error resolving json into ap vocab type: %s", err)
}
diff --git a/internal/federation/dereferencing/instance.go b/internal/federation/dereferencing/instance.go
index ec3c3f13d..775475749 100644
--- a/internal/federation/dereferencing/instance.go
+++ b/internal/federation/dereferencing/instance.go
@@ -36,5 +36,5 @@ func (d *deref) GetRemoteInstance(ctx context.Context, username string, remoteIn
return nil, fmt.Errorf("transport err: %s", err)
}
- return transport.DereferenceInstance(context.Background(), remoteInstanceURI)
+ return transport.DereferenceInstance(ctx, remoteInstanceURI)
}
diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go
index edf1f0e41..435bc9217 100644
--- a/internal/federation/dereferencing/status.go
+++ b/internal/federation/dereferencing/status.go
@@ -137,7 +137,7 @@ func (d *deref) dereferenceStatusable(ctx context.Context, username string, remo
return nil, fmt.Errorf("DereferenceStatusable: transport err: %s", err)
}
- b, err := transport.Dereference(context.Background(), remoteStatusID)
+ b, err := transport.Dereference(ctx, remoteStatusID)
if err != nil {
return nil, fmt.Errorf("DereferenceStatusable: error deferencing %s: %s", remoteStatusID.String(), err)
}
@@ -147,7 +147,7 @@ func (d *deref) dereferenceStatusable(ctx context.Context, username string, remo
return nil, fmt.Errorf("DereferenceStatusable: error unmarshalling bytes into json: %s", err)
}
- t, err := streams.ToType(context.Background(), m)
+ t, err := streams.ToType(ctx, m)
if err != nil {
return nil, fmt.Errorf("DereferenceStatusable: error resolving json into ap vocab type: %s", err)
}
diff --git a/internal/federation/federatingdb/accept.go b/internal/federation/federatingdb/accept.go
index 477c5e8b9..3bd84849d 100644
--- a/internal/federation/federatingdb/accept.go
+++ b/internal/federation/federatingdb/accept.go
@@ -20,11 +20,9 @@ package federatingdb
import (
"context"
- "encoding/json"
"errors"
"fmt"
- "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/ap"
@@ -37,43 +35,29 @@ import (
func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) error {
l := f.log.WithFields(
logrus.Fields{
- "func": "Accept",
- "asType": accept.GetTypeName(),
+ "func": "Accept",
},
)
- m, err := streams.Serialize(accept)
- if err != nil {
- return err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(accept)
+ if err != nil {
+ return err
+ }
+ l = l.WithField("accept", i)
+ l.Debug("entering Accept")
}
- b, err := json.Marshal(m)
+
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
- l.Debugf("received ACCEPT asType %s", string(b))
-
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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,
+ 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
+ // 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
}
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("ACCEPT: target account was set on context but couldn't be parsed")
- return nil
- }
-
- fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
- if fromFederatorChanI == nil {
- l.Error("ACCEPT: from federator channel wasn't set on context")
- return nil
- }
- fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
- if !ok {
- l.Error("ACCEPT: from federator channel was set on context but couldn't be parsed")
- return nil
- }
acceptObject := accept.GetActivityStreamsObject()
if acceptObject == nil {
diff --git a/internal/federation/federatingdb/announce.go b/internal/federation/federatingdb/announce.go
index 7d7b12cbc..e089f7e42 100644
--- a/internal/federation/federatingdb/announce.go
+++ b/internal/federation/federatingdb/announce.go
@@ -20,16 +20,12 @@ package federatingdb
import (
"context"
- "encoding/json"
"fmt"
- "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/ap"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/messages"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error {
@@ -38,40 +34,26 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre
"func": "Announce",
},
)
- m, err := streams.Serialize(announce)
- if err != nil {
- return err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(announce)
+ if err != nil {
+ return err
+ }
+ l = l.WithField("announce", i)
+ l.Debug("entering Announce")
}
- b, err := json.Marshal(m)
+
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
-
- l.Debugf("received ANNOUNCE %s", string(b))
-
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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,
+ 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
+ // 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
}
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("ANNOUNCE: target account was set on context but couldn't be parsed")
- return nil
- }
-
- fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
- if fromFederatorChanI == nil {
- l.Error("ANNOUNCE: from federator channel wasn't set on context")
- return nil
- }
- fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
- if !ok {
- l.Error("ANNOUNCE: from federator channel was set on context but couldn't be parsed")
- return nil
- }
boost, isNew, err := f.typeConverter.ASAnnounceToStatus(ctx, announce)
if err != nil {
diff --git a/internal/federation/federatingdb/create.go b/internal/federation/federatingdb/create.go
index 88b0d1e8b..474890c34 100644
--- a/internal/federation/federatingdb/create.go
+++ b/internal/federation/federatingdb/create.go
@@ -20,19 +20,15 @@ package federatingdb
import (
"context"
- "encoding/json"
"errors"
"fmt"
- "github.com/go-fed/activity/streams"
"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"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// Create adds a new entry to the database which must be able to be
@@ -50,44 +46,29 @@ import (
func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
l := f.log.WithFields(
logrus.Fields{
- "func": "Create",
- "asType": asType.GetTypeName(),
+ "func": "Create",
},
)
- m, err := streams.Serialize(asType)
- if err != nil {
- return err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(asType)
+ if err != nil {
+ return err
+ }
+ l = l.WithField("create", i)
+ l.Debug("entering Create")
}
- b, err := json.Marshal(m)
+
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
-
- l.Debugf("received CREATE asType %s", string(b))
-
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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,
+ 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
+ // 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
}
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("CREATE: target account was set on context but couldn't be parsed")
- return nil
- }
-
- fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
- if fromFederatorChanI == nil {
- l.Error("CREATE: from federator channel wasn't set on context")
- return nil
- }
- fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
- if !ok {
- l.Error("CREATE: from federator channel was set on context but couldn't be parsed")
- return nil
- }
switch asType.GetTypeName() {
case ap.ActivityCreate:
diff --git a/internal/federation/federatingdb/delete.go b/internal/federation/federatingdb/delete.go
index 9aa36ee90..fc77f8025 100644
--- a/internal/federation/federatingdb/delete.go
+++ b/internal/federation/federatingdb/delete.go
@@ -27,7 +27,6 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/messages"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// Delete removes the entry with the given id.
@@ -40,32 +39,19 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
l := f.log.WithFields(
logrus.Fields{
"func": "Delete",
- "id": id.String(),
+ "id": id,
},
)
- l.Debugf("received DELETE id %s", id.String())
+ l.Debug("entering Delete")
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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
- }
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("DELETE: target account was set on context but couldn't be parsed")
- return nil
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
+ if err != nil {
+ return err
}
-
- fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
- if fromFederatorChanI == nil {
- l.Error("DELETE: from federator channel wasn't set on context")
- return nil
- }
- fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
- if !ok {
- l.Error("DELETE: from federator channel was set on context but couldn't be parsed")
+ 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
+ // 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
}
diff --git a/internal/federation/federatingdb/exists.go b/internal/federation/federatingdb/exists.go
index 0e13c1196..ec5599c24 100644
--- a/internal/federation/federatingdb/exists.go
+++ b/internal/federation/federatingdb/exists.go
@@ -29,14 +29,15 @@ import (
// id. It may not be owned by this application instance.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either.
func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) {
l := f.log.WithFields(
logrus.Fields{
"func": "Exists",
- "id": id.String(),
+ "id": id,
},
)
- l.Debugf("entering EXISTS function with id %s", id.String())
-
+ l.Debug("entering Exists")
return false, nil
}
diff --git a/internal/federation/federatingdb/federatingdb_test.go b/internal/federation/federatingdb/federatingdb_test.go
index f32314b10..fc78540f2 100644
--- a/internal/federation/federatingdb/federatingdb_test.go
+++ b/internal/federation/federatingdb/federatingdb_test.go
@@ -18,4 +18,55 @@
package federatingdb_test
-// TODO: write tests for pgfed
+import (
+ "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/typeutils"
+ "github.com/superseriousbusiness/gotosocial/testrig"
+)
+
+type FederatingDBTestSuite struct {
+ suite.Suite
+ config *config.Config
+ db db.DB
+ log *logrus.Logger
+ tc typeutils.TypeConverter
+ federatingDB federatingdb.DB
+
+ testTokens map[string]*gtsmodel.Token
+ testClients map[string]*gtsmodel.Client
+ testApplications map[string]*gtsmodel.Application
+ testUsers map[string]*gtsmodel.User
+ testAccounts map[string]*gtsmodel.Account
+ testAttachments map[string]*gtsmodel.MediaAttachment
+ testStatuses map[string]*gtsmodel.Status
+ testBlocks map[string]*gtsmodel.Block
+}
+
+func (suite *FederatingDBTestSuite) SetupSuite() {
+ suite.testTokens = testrig.NewTestTokens()
+ suite.testClients = testrig.NewTestClients()
+ suite.testApplications = testrig.NewTestApplications()
+ suite.testUsers = testrig.NewTestUsers()
+ suite.testAccounts = testrig.NewTestAccounts()
+ suite.testAttachments = testrig.NewTestAttachments()
+ suite.testStatuses = testrig.NewTestStatuses()
+ suite.testBlocks = testrig.NewTestBlocks()
+}
+
+func (suite *FederatingDBTestSuite) SetupTest() {
+ suite.config = testrig.NewTestConfig()
+ suite.db = testrig.NewTestDB()
+ suite.tc = testrig.NewTestTypeConverter(suite.db)
+ suite.log = testrig.NewTestLog()
+ suite.federatingDB = testrig.NewTestFederatingDB(suite.db)
+ testrig.StandardDBSetup(suite.db, suite.testAccounts)
+}
+
+func (suite *FederatingDBTestSuite) TearDownTest() {
+ testrig.StandardDBTeardown(suite.db)
+}
diff --git a/internal/federation/federatingdb/followers.go b/internal/federation/federatingdb/followers.go
index 69c68b8b9..61c5d4287 100644
--- a/internal/federation/federatingdb/followers.go
+++ b/internal/federation/federatingdb/followers.go
@@ -5,12 +5,9 @@ import (
"fmt"
"net/url"
- "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/db"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// Followers obtains the Followers Collection for an actor with the
@@ -22,39 +19,28 @@ import (
func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
l := f.log.WithFields(
logrus.Fields{
- "func": "Followers",
- "actorIRI": actorIRI.String(),
+ "func": "Followers",
+ "id": actorIRI,
},
)
- l.Debugf("entering FOLLOWERS function with actorIRI %s", actorIRI.String())
+ l.Debug("entering Followers")
- acct := &gtsmodel.Account{}
-
- if util.IsUserPath(actorIRI) {
- acct, err = f.db.GetAccountByURI(ctx, actorIRI.String())
- if err != nil {
- return nil, fmt.Errorf("FOLLOWERS: db error getting account with uri %s: %s", actorIRI.String(), err)
- }
- } else if util.IsFollowersPath(actorIRI) {
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: actorIRI.String()}}, acct); err != nil {
- return nil, fmt.Errorf("FOLLOWERS: db error getting account with followers uri %s: %s", actorIRI.String(), err)
- }
- } else {
- return nil, fmt.Errorf("FOLLOWERS: could not parse actor IRI %s as users or followers path", actorIRI.String())
+ acct, err := f.getAccountForIRI(ctx, actorIRI)
+ if err != nil {
+ return nil, err
}
acctFollowers, err := f.db.GetAccountFollowedBy(ctx, acct.ID, false)
if err != nil {
- return nil, fmt.Errorf("FOLLOWERS: db error getting followers for account id %s: %s", acct.ID, err)
+ return nil, fmt.Errorf("Followers: db error getting followers for account id %s: %s", acct.ID, err)
}
- followers = streams.NewActivityStreamsCollection()
- items := streams.NewActivityStreamsItemsProperty()
+ iris := []*url.URL{}
for _, follow := range acctFollowers {
if follow.Account == nil {
- followAccount, err := f.db.GetAccountByID(ctx, follow.AccountID)
+ a, err := f.db.GetAccountByID(ctx, follow.AccountID)
if err != nil {
- errWrapped := fmt.Errorf("FOLLOWERS: db error getting account id %s: %s", follow.AccountID, err)
+ errWrapped := fmt.Errorf("Followers: db error getting account id %s: %s", follow.AccountID, err)
if err == db.ErrNoEntries {
// no entry for this account id so it's probably been deleted and we haven't caught up yet
l.Error(errWrapped)
@@ -64,15 +50,14 @@ func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (follow
return nil, errWrapped
}
}
- follow.Account = followAccount
+ follow.Account = a
}
-
- uri, err := url.Parse(follow.Account.URI)
+ u, err := url.Parse(follow.Account.URI)
if err != nil {
- return nil, fmt.Errorf("FOLLOWERS: error parsing %s as url: %s", follow.Account.URI, err)
+ return nil, err
}
- items.AppendIRI(uri)
+ iris = append(iris, u)
}
- followers.SetActivityStreamsItems(items)
- return
+
+ return f.collectIRIs(ctx, iris)
}
diff --git a/internal/federation/federatingdb/followers_test.go b/internal/federation/federatingdb/followers_test.go
new file mode 100644
index 000000000..d993a7201
--- /dev/null
+++ b/internal/federation/federatingdb/followers_test.go
@@ -0,0 +1,53 @@
+/*
+ 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"
+ "encoding/json"
+ "testing"
+
+ "github.com/go-fed/activity/streams"
+ "github.com/stretchr/testify/suite"
+ "github.com/superseriousbusiness/gotosocial/testrig"
+)
+
+type FollowersTestSuite struct {
+ FederatingDBTestSuite
+}
+
+func (suite *FollowersTestSuite) TestGetFollowers() {
+ testAccount := suite.testAccounts["local_account_2"]
+
+ f, err := suite.federatingDB.Followers(context.Background(), testrig.URLMustParse(testAccount.URI))
+ suite.NoError(err)
+
+ fi, err := streams.Serialize(f)
+ suite.NoError(err)
+
+ fJson, err := json.Marshal(fi)
+ suite.NoError(err)
+
+ // zork follows local_account_2 so this should be reflected in the response
+ suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","items":"http://localhost:8080/users/the_mighty_zork","type":"Collection"}`, string(fJson))
+}
+
+func TestFollowersTestSuite(t *testing.T) {
+ suite.Run(t, &FollowersTestSuite{})
+}
diff --git a/internal/federation/federatingdb/following.go b/internal/federation/federatingdb/following.go
index a36f4e203..2cc024832 100644
--- a/internal/federation/federatingdb/following.go
+++ b/internal/federation/federatingdb/following.go
@@ -5,12 +5,9 @@ import (
"fmt"
"net/url"
- "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/db"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// Following obtains the Following Collection for an actor with the
@@ -22,53 +19,28 @@ import (
func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) {
l := f.log.WithFields(
logrus.Fields{
- "func": "Following",
- "actorIRI": actorIRI.String(),
+ "func": "Following",
+ "id": actorIRI,
},
)
- l.Debugf("entering FOLLOWING function with actorIRI %s", actorIRI.String())
+ l.Debug("entering Following")
- var acct *gtsmodel.Account
- if util.IsUserPath(actorIRI) {
- username, err := util.ParseUserPath(actorIRI)
- if err != nil {
- return nil, fmt.Errorf("FOLLOWING: error parsing user path: %s", err)
- }
-
- a, err := f.db.GetLocalAccountByUsername(ctx, username)
- if err != nil {
- return nil, fmt.Errorf("FOLLOWING: db error getting account with uri %s: %s", actorIRI.String(), err)
- }
-
- acct = a
- } else if util.IsFollowingPath(actorIRI) {
- username, err := util.ParseFollowingPath(actorIRI)
- if err != nil {
- return nil, fmt.Errorf("FOLLOWING: error parsing following path: %s", err)
- }
-
- a, err := f.db.GetLocalAccountByUsername(ctx, username)
- if err != nil {
- return nil, fmt.Errorf("FOLLOWING: db error getting account with following uri %s: %s", actorIRI.String(), err)
- }
-
- acct = a
- } else {
- return nil, fmt.Errorf("FOLLOWING: could not parse actor IRI %s as users or following path", actorIRI.String())
+ acct, err := f.getAccountForIRI(ctx, actorIRI)
+ if err != nil {
+ return nil, err
}
acctFollowing, err := f.db.GetAccountFollows(ctx, acct.ID)
if err != nil {
- return nil, fmt.Errorf("FOLLOWING: db error getting following for account id %s: %s", acct.ID, err)
+ return nil, fmt.Errorf("Following: db error getting following for account id %s: %s", acct.ID, err)
}
- following = streams.NewActivityStreamsCollection()
- items := streams.NewActivityStreamsItemsProperty()
+ iris := []*url.URL{}
for _, follow := range acctFollowing {
- if follow.Account == nil {
- followAccount, err := f.db.GetAccountByID(ctx, follow.AccountID)
+ if follow.TargetAccount == nil {
+ a, err := f.db.GetAccountByID(ctx, follow.TargetAccountID)
if err != nil {
- errWrapped := fmt.Errorf("FOLLOWING: db error getting account id %s: %s", follow.AccountID, err)
+ errWrapped := fmt.Errorf("Following: db error getting account id %s: %s", follow.TargetAccountID, err)
if err == db.ErrNoEntries {
// no entry for this account id so it's probably been deleted and we haven't caught up yet
l.Error(errWrapped)
@@ -78,15 +50,14 @@ func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (follow
return nil, errWrapped
}
}
- follow.Account = followAccount
+ follow.TargetAccount = a
}
-
- uri, err := url.Parse(follow.Account.URI)
+ u, err := url.Parse(follow.TargetAccount.URI)
if err != nil {
- return nil, fmt.Errorf("FOLLOWING: error parsing %s as url: %s", follow.Account.URI, err)
+ return nil, err
}
- items.AppendIRI(uri)
+ iris = append(iris, u)
}
- following.SetActivityStreamsItems(items)
- return
+
+ return f.collectIRIs(ctx, iris)
}
diff --git a/internal/federation/federatingdb/following_test.go b/internal/federation/federatingdb/following_test.go
new file mode 100644
index 000000000..7788840d7
--- /dev/null
+++ b/internal/federation/federatingdb/following_test.go
@@ -0,0 +1,53 @@
+/*
+ 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"
+ "encoding/json"
+ "testing"
+
+ "github.com/go-fed/activity/streams"
+ "github.com/stretchr/testify/suite"
+ "github.com/superseriousbusiness/gotosocial/testrig"
+)
+
+type FollowingTestSuite struct {
+ FederatingDBTestSuite
+}
+
+func (suite *FollowingTestSuite) TestGetFollowing() {
+ testAccount := suite.testAccounts["local_account_1"]
+
+ f, err := suite.federatingDB.Following(context.Background(), testrig.URLMustParse(testAccount.URI))
+ suite.NoError(err)
+
+ fi, err := streams.Serialize(f)
+ suite.NoError(err)
+
+ fJson, err := json.Marshal(fi)
+ suite.NoError(err)
+
+ // zork follows admin account and local_account_1
+ suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","items":["http://localhost:8080/users/admin","http://localhost:8080/users/1happyturtle"],"type":"Collection"}`, string(fJson))
+}
+
+func TestFollowingTestSuite(t *testing.T) {
+ suite.Run(t, &FollowingTestSuite{})
+}
diff --git a/internal/federation/federatingdb/get.go b/internal/federation/federatingdb/get.go
index cc04dd851..505891ca4 100644
--- a/internal/federation/federatingdb/get.go
+++ b/internal/federation/federatingdb/get.go
@@ -25,8 +25,6 @@ import (
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
- "github.com/superseriousbusiness/gotosocial/internal/db"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
@@ -37,46 +35,33 @@ func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type,
l := f.log.WithFields(
logrus.Fields{
"func": "Get",
- "id": id.String(),
+ "id": id,
},
)
- l.Debug("entering GET function")
+ l.Debug("entering Get")
if util.IsUserPath(id) {
acct, err := f.db.GetAccountByURI(ctx, id.String())
if err != nil {
return nil, err
}
- l.Debug("is user path! returning account")
return f.typeConverter.AccountToAS(ctx, acct)
}
- if util.IsFollowersPath(id) {
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: id.String()}}, acct); err != nil {
- return nil, err
- }
-
- followersURI, err := url.Parse(acct.FollowersURI)
+ if util.IsStatusesPath(id) {
+ status, err := f.db.GetStatusByURI(ctx, id.String())
if err != nil {
return nil, err
}
+ return f.typeConverter.StatusToAS(ctx, status)
+ }
- return f.Followers(ctx, followersURI)
+ if util.IsFollowersPath(id) {
+ return f.Followers(ctx, id)
}
if util.IsFollowingPath(id) {
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "following_uri", Value: id.String()}}, acct); err != nil {
- return nil, err
- }
-
- followingURI, err := url.Parse(acct.FollowingURI)
- if err != nil {
- return nil, err
- }
-
- return f.Following(ctx, followingURI)
+ return f.Following(ctx, id)
}
return nil, errors.New("could not get")
diff --git a/internal/federation/federatingdb/inbox.go b/internal/federation/federatingdb/inbox.go
index 4390a8b4b..95886b571 100644
--- a/internal/federation/federatingdb/inbox.go
+++ b/internal/federation/federatingdb/inbox.go
@@ -20,44 +20,19 @@ package federatingdb
import (
"context"
- "fmt"
"net/url"
- "github.com/go-fed/activity/pub"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
- "github.com/sirupsen/logrus"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// InboxContains returns true if the OrderedCollection at 'inbox'
// contains the specified 'id'.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we have our own logic for inboxes so always return false here.
func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "InboxContains",
- "id": id.String(),
- },
- )
- l.Debugf("entering INBOXCONTAINS function with for inbox %s and id %s", inbox.String(), id.String())
-
- if !util.IsInboxPath(inbox) {
- return false, fmt.Errorf("%s is not an inbox URI", inbox.String())
- }
-
- activityI := c.Value(util.APActivity)
- if activityI == nil {
- return false, fmt.Errorf("no activity was set for id %s", id.String())
- }
- activity, ok := activityI.(pub.Activity)
- if !ok || activity == nil {
- return false, fmt.Errorf("could not parse contextual activity for id %s", id.String())
- }
-
- l.Debugf("activity type %s for id %s", activity.GetTypeName(), id.String())
-
return false, nil
}
@@ -65,13 +40,9 @@ func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (con
// the specified IRI, for prepending new items.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we don't (yet) serve inboxes, so just return empty and nil here.
func (f *federatingDB) GetInbox(c context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "GetInbox",
- },
- )
- l.Debugf("entering GETINBOX function with inboxIRI %s", inboxIRI.String())
return streams.NewActivityStreamsOrderedCollectionPage(), nil
}
@@ -80,12 +51,8 @@ func (f *federatingDB) GetInbox(c context.Context, inboxIRI *url.URL) (inbox voc
// database entries. Separate calls to Create will do that.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we don't allow inbox setting so just return nil here.
func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "SetInbox",
- },
- )
- l.Debug("entering SETINBOX function")
return nil
}
diff --git a/internal/federation/federatingdb/liked.go b/internal/federation/federatingdb/liked.go
index b85398fef..93b3d2c88 100644
--- a/internal/federation/federatingdb/liked.go
+++ b/internal/federation/federatingdb/liked.go
@@ -22,8 +22,8 @@ import (
"context"
"net/url"
+ "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
- "github.com/sirupsen/logrus"
)
// Liked obtains the Liked Collection for an actor with the
@@ -32,13 +32,8 @@ import (
// If modified, the library will then call Update.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we don't serve a Liked collection *yet* so just return an empty collection for now.
func (f *federatingDB) Liked(c context.Context, actorIRI *url.URL) (liked vocab.ActivityStreamsCollection, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "Liked",
- "actorIRI": actorIRI.String(),
- },
- )
- l.Debugf("entering LIKED function with actorIRI %s", actorIRI.String())
- return nil, nil
+ return streams.NewActivityStreamsCollection(), nil
}
diff --git a/internal/federation/federatingdb/outbox.go b/internal/federation/federatingdb/outbox.go
index 81b90aae2..07caf999e 100644
--- a/internal/federation/federatingdb/outbox.go
+++ b/internal/federation/federatingdb/outbox.go
@@ -20,29 +20,19 @@ package federatingdb
import (
"context"
- "fmt"
"net/url"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
- "github.com/sirupsen/logrus"
- "github.com/superseriousbusiness/gotosocial/internal/db"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/util"
)
// GetOutbox returns the first ordered collection page of the outbox
// at the specified IRI, for prepending new items.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we don't (yet) serve outboxes, so just return empty and nil here.
func (f *federatingDB) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "GetOutbox",
- },
- )
- l.Debug("entering GETOUTBOX function")
-
return streams.NewActivityStreamsOrderedCollectionPage(), nil
}
@@ -51,14 +41,9 @@ func (f *federatingDB) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox
// database entries. Separate calls to Create will do that.
//
// The library makes this call only after acquiring a lock first.
+//
+// Implementation note: we don't allow outbox setting so just return nil here.
func (f *federatingDB) SetOutbox(ctx context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "SetOutbox",
- },
- )
- l.Debug("entering SETOUTBOX function")
-
return nil
}
@@ -67,23 +52,9 @@ func (f *federatingDB) SetOutbox(ctx context.Context, outbox vocab.ActivityStrea
//
// The library makes this call only after acquiring a lock first.
func (f *federatingDB) OutboxForInbox(ctx context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "OutboxForInbox",
- "inboxIRI": inboxIRI.String(),
- },
- )
- l.Debugf("entering OUTBOXFORINBOX function with inboxIRI %s", inboxIRI.String())
-
- if !util.IsInboxPath(inboxIRI) {
- return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
- }
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
- if err == db.ErrNoEntries {
- return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
- }
- return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String())
+ acct, err := f.getAccountForIRI(ctx, inboxIRI)
+ if err != nil {
+ return nil, err
}
return url.Parse(acct.OutboxURI)
}
diff --git a/internal/federation/federatingdb/owns.go b/internal/federation/federatingdb/owns.go
index 1c1f2512d..04a417490 100644
--- a/internal/federation/federatingdb/owns.go
+++ b/internal/federation/federatingdb/owns.go
@@ -36,10 +36,10 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
l := f.log.WithFields(
logrus.Fields{
"func": "Owns",
- "id": id.String(),
+ "id": id,
},
)
- l.Tracef("entering OWNS function with id %s", id.String())
+ l.Debug("entering Owns")
// if the id host isn't this instance host, we don't own this IRI
if id.Host != f.config.Host {
diff --git a/internal/federation/federatingdb/undo.go b/internal/federation/federatingdb/undo.go
index 481c2d787..9fcb6ce1a 100644
--- a/internal/federation/federatingdb/undo.go
+++ b/internal/federation/federatingdb/undo.go
@@ -20,48 +20,42 @@ package federatingdb
import (
"context"
- "encoding/json"
"errors"
"fmt"
- "github.com/go-fed/activity/streams"
"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/util"
)
func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo) error {
l := f.log.WithFields(
logrus.Fields{
- "func": "Undo",
- "asType": undo.GetTypeName(),
+ "func": "Undo",
},
)
- m, err := streams.Serialize(undo)
- if err != nil {
- return err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(undo)
+ if err != nil {
+ return err
+ }
+ l = l.WithField("undo", i)
+ l.Debug("entering Undo")
}
- b, err := json.Marshal(m)
+
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
- l.Debugf("received UNDO asType %s", string(b))
-
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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,
+ 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
+ // 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
}
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("UNDO: target account was set on context but couldn't be parsed")
- return nil
- }
undoObject := undo.GetActivityStreamsObject()
if undoObject == nil {
diff --git a/internal/federation/federatingdb/update.go b/internal/federation/federatingdb/update.go
index 5dec2bd69..9e7bd3d5b 100644
--- a/internal/federation/federatingdb/update.go
+++ b/internal/federation/federatingdb/update.go
@@ -20,11 +20,9 @@ package federatingdb
import (
"context"
- "encoding/json"
"errors"
"fmt"
- "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/ap"
@@ -45,35 +43,32 @@ import (
func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l := f.log.WithFields(
logrus.Fields{
- "func": "Update",
- "asType": asType.GetTypeName(),
+ "func": "Update",
},
)
- m, err := streams.Serialize(asType)
- if err != nil {
- return err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(asType)
+ if err != nil {
+ return err
+ }
+ l = l.WithField("update", i)
+ l.Debug("entering Update")
}
- b, err := json.Marshal(m)
+
+ targetAcct, fromFederatorChan, err := extractFromCtx(ctx)
if err != nil {
return err
}
-
- l.Debugf("received UPDATE asType %s", string(b))
-
- targetAcctI := ctx.Value(util.APAccount)
- if targetAcctI == nil {
- // If the target account 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,
+ 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
+ // 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
}
- targetAcct, ok := targetAcctI.(*gtsmodel.Account)
- if !ok {
- l.Error("UPDATE: target account was set on context but couldn't be parsed")
- }
requestingAcctI := ctx.Value(util.APRequestingAccount)
- if targetAcctI == nil {
+ if requestingAcctI == nil {
l.Error("UPDATE: requesting account wasn't set on context")
}
requestingAcct, ok := requestingAcctI.(*gtsmodel.Account)
@@ -81,15 +76,6 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l.Error("UPDATE: requesting account was set on context but couldn't be parsed")
}
- fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
- if fromFederatorChanI == nil {
- l.Error("UPDATE: from federator channel wasn't set on context")
- }
- fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)
- if !ok {
- l.Error("UPDATE: from federator channel was set on context but couldn't be parsed")
- }
-
typeName := asType.GetTypeName()
if typeName == ap.ActorApplication ||
typeName == ap.ActorGroup ||
diff --git a/internal/federation/federatingdb/util.go b/internal/federation/federatingdb/util.go
index d8c7d8e8a..d719bf16d 100644
--- a/internal/federation/federatingdb/util.go
+++ b/internal/federation/federatingdb/util.go
@@ -32,6 +32,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/id"
+ "github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
@@ -64,19 +65,18 @@ func sameActor(activityActor vocab.ActivityStreamsActorProperty, followActor voc
func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL, err error) {
l := f.log.WithFields(
logrus.Fields{
- "func": "NewID",
- "asType": t.GetTypeName(),
+ "func": "NewID",
},
)
- m, err := streams.Serialize(t)
- if err != nil {
- return nil, err
- }
- b, err := json.Marshal(m)
- if err != nil {
- return nil, err
+
+ if l.Level >= logrus.DebugLevel {
+ i, err := marshalItem(t)
+ if err != nil {
+ return nil, err
+ }
+ l = l.WithField("newID", i)
+ l.Debug("entering NewID")
}
- l.Debugf("received NEWID request for asType %s", string(b))
switch t.GetTypeName() {
case ap.ActivityFollow:
@@ -201,23 +201,9 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,
//
// The library makes this call only after acquiring a lock first.
func (f *federatingDB) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "ActorForOutbox",
- "inboxIRI": outboxIRI.String(),
- },
- )
- l.Debugf("entering ACTORFOROUTBOX function with outboxIRI %s", outboxIRI.String())
-
- if !util.IsOutboxPath(outboxIRI) {
- return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String())
- }
- acct := &gtsmodel.Account{}
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "outbox_uri", Value: outboxIRI.String()}}, acct); err != nil {
- if err == db.ErrNoEntries {
- return nil, fmt.Errorf("no actor found that corresponds to outbox %s", outboxIRI.String())
- }
- return nil, fmt.Errorf("db error searching for actor with outbox %s", outboxIRI.String())
+ acct, err := f.getAccountForIRI(ctx, outboxIRI)
+ if err != nil {
+ return nil, err
}
return url.Parse(acct.URI)
}
@@ -226,23 +212,116 @@ func (f *federatingDB) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (
//
// The library makes this call only after acquiring a lock first.
func (f *federatingDB) ActorForInbox(ctx context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) {
- l := f.log.WithFields(
- logrus.Fields{
- "func": "ActorForInbox",
- "inboxIRI": inboxIRI.String(),
- },
- )
- l.Debugf("entering ACTORFORINBOX function with inboxIRI %s", inboxIRI.String())
-
- if !util.IsInboxPath(inboxIRI) {
- return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
+ acct, err := f.getAccountForIRI(ctx, inboxIRI)
+ if err != nil {
+ return nil, err
}
+ return url.Parse(acct.URI)
+}
+
+// getAccountForIRI returns the account that corresponds to or owns the given IRI.
+func (f *federatingDB) getAccountForIRI(ctx context.Context, iri *url.URL) (account *gtsmodel.Account, err error) {
acct := &gtsmodel.Account{}
- if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
- if err == db.ErrNoEntries {
- return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
+
+ if util.IsInboxPath(iri) {
+ if err := f.db.GetWhere(ctx, []db.Where{{Key: "inbox_uri", Value: iri.String()}}, acct); err != nil {
+ if err == db.ErrNoEntries {
+ return nil, fmt.Errorf("no actor found that corresponds to inbox %s", iri.String())
+ }
+ return nil, fmt.Errorf("db error searching for actor with inbox %s", iri.String())
}
- return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String())
+ return acct, nil
}
- return url.Parse(acct.URI)
+
+ if util.IsOutboxPath(iri) {
+ if err := f.db.GetWhere(ctx, []db.Where{{Key: "outbox_uri", Value: iri.String()}}, acct); err != nil {
+ if err == db.ErrNoEntries {
+ return nil, fmt.Errorf("no actor found that corresponds to outbox %s", iri.String())
+ }
+ return nil, fmt.Errorf("db error searching for actor with outbox %s", iri.String())
+ }
+ return acct, nil
+ }
+
+ if util.IsUserPath(iri) {
+ if err := f.db.GetWhere(ctx, []db.Where{{Key: "uri", Value: iri.String()}}, acct); err != nil {
+ if err == db.ErrNoEntries {
+ return nil, fmt.Errorf("no actor found that corresponds to uri %s", iri.String())
+ }
+ return nil, fmt.Errorf("db error searching for actor with uri %s", iri.String())
+ }
+ return acct, nil
+ }
+
+ if util.IsFollowersPath(iri) {
+ if err := f.db.GetWhere(ctx, []db.Where{{Key: "followers_uri", Value: iri.String()}}, acct); err != nil {
+ if err == db.ErrNoEntries {
+ return nil, fmt.Errorf("no actor found that corresponds to followers_uri %s", iri.String())
+ }
+ return nil, fmt.Errorf("db error searching for actor with followers_uri %s", iri.String())
+ }
+ return acct, nil
+ }
+
+ if util.IsFollowingPath(iri) {
+ if err := f.db.GetWhere(ctx, []db.Where{{Key: "following_uri", Value: iri.String()}}, acct); err != nil {
+ if err == db.ErrNoEntries {
+ return nil, fmt.Errorf("no actor found that corresponds to following_uri %s", iri.String())
+ }
+ return nil, fmt.Errorf("db error searching for actor with following_uri %s", iri.String())
+ }
+ return acct, nil
+ }
+
+ return nil, fmt.Errorf("getActorForIRI: iri %s not recognised", iri)
+}
+
+// collectFollows takes a slice of iris and converts them into ActivityStreamsCollection of IRIs.
+func (f *federatingDB) collectIRIs(ctx context.Context, iris []*url.URL) (vocab.ActivityStreamsCollection, error) {
+ collection := streams.NewActivityStreamsCollection()
+ items := streams.NewActivityStreamsItemsProperty()
+ for _, i := range iris {
+ items.AppendIRI(i)
+ }
+ collection.SetActivityStreamsItems(items)
+ return collection, nil
+}
+
+// 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.
+// - 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")
+ }
+ }
+
+ 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")
+ }
+ }
+
+ return targetAcct, fromFederatorChan, nil
+}
+
+func marshalItem(item vocab.Type) (string, error) {
+ m, err := streams.Serialize(item)
+ if err != nil {
+ return "", err
+ }
+ b, err := json.Marshal(m)
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
}
diff --git a/internal/federation/finger.go b/internal/federation/finger.go
index 5cdd4c04d..ef7896b86 100644
--- a/internal/federation/finger.go
+++ b/internal/federation/finger.go
@@ -39,7 +39,7 @@ func (f *federator) FingerRemoteAccount(ctx context.Context, requestingUsername
return nil, fmt.Errorf("FingerRemoteAccount: error getting transport for username %s while dereferencing @%s@%s: %s", requestingUsername, targetUsername, targetDomain, err)
}
- b, err := t.Finger(context.Background(), targetUsername, targetDomain)
+ b, err := t.Finger(ctx, targetUsername, targetDomain)
if err != nil {
return nil, fmt.Errorf("FingerRemoteAccount: error doing request on behalf of username %s while dereferencing @%s@%s: %s", requestingUsername, targetUsername, targetDomain, err)
}