diff options
author | 2022-05-23 11:46:50 +0200 | |
---|---|---|
committer | 2022-05-23 11:46:50 +0200 | |
commit | 469da93678b3f738f65372d13dcd1ea7de390063 (patch) | |
tree | 33d6b5b9facd3cf242235fbfb5f9275051864923 /internal/federation/federatingprotocol_test.go | |
parent | [docs] Add Caddy instructions to the documentation (#594) (diff) | |
download | gotosocial-469da93678b3f738f65372d13dcd1ea7de390063.tar.xz |
[security] Check all involved IRIs during block checking (#593)
* tidy up context keys, add otherInvolvedIRIs
* add ReplyToable interface
* skip block check if we own the requesting domain
* add block check for other involved IRIs
* use cacheable status fetch
* remove unused ContextActivity
* remove unused ContextActivity
* add helper for unique URIs
* check through CCs and clean slice
* add GetAccountIDForStatusURI
* add GetAccountIDForAccountURI
* check blocks on involved account
* add statuses to tests
* add some blocked tests
* go fmt
* extract Tos as well as CCs
* test PostInboxRequestBodyHook
* add some more testActivities
* deduplicate involvedAccountIDs
* go fmt
* use cacheable db functions, remove new functions
Diffstat (limited to 'internal/federation/federatingprotocol_test.go')
-rw-r--r-- | internal/federation/federatingprotocol_test.go | 210 |
1 files changed, 198 insertions, 12 deletions
diff --git a/internal/federation/federatingprotocol_test.go b/internal/federation/federatingprotocol_test.go index b4769a70f..992a55e6b 100644 --- a/internal/federation/federatingprotocol_test.go +++ b/internal/federation/federatingprotocol_test.go @@ -22,11 +22,11 @@ import ( "context" "net/http" "net/http/httptest" + "net/url" "testing" "github.com/go-fed/httpsig" "github.com/stretchr/testify/suite" - "github.com/superseriousbusiness/activity/pub" "github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/concurrency" "github.com/superseriousbusiness/gotosocial/internal/federation" @@ -39,8 +39,7 @@ type FederatingProtocolTestSuite struct { FederatorStandardTestSuite } -// make sure PostInboxRequestBodyHook properly sets the inbox username and activity on the context -func (suite *FederatingProtocolTestSuite) TestPostInboxRequestBodyHook() { +func (suite *FederatingProtocolTestSuite) TestPostInboxRequestBodyHook1() { // the activity we're gonna use activity := suite.testActivities["dm_for_zork"] @@ -63,13 +62,82 @@ func (suite *FederatingProtocolTestSuite) TestPostInboxRequestBodyHook() { suite.NoError(err) suite.NotNil(newContext) - // activity should be set on context now - activityI := newContext.Value(ap.ContextActivity) - suite.NotNil(activityI) - returnedActivity, ok := activityI.(pub.Activity) - suite.True(ok) - suite.NotNil(returnedActivity) - suite.EqualValues(activity.Activity, returnedActivity) + involvedIRIsI := newContext.Value(ap.ContextOtherInvolvedIRIs) + involvedIRIs, ok := involvedIRIsI.([]*url.URL) + if !ok { + suite.FailNow("couldn't get involved IRIs from context") + } + + suite.Len(involvedIRIs, 1) + suite.Contains(involvedIRIs, testrig.URLMustParse("http://localhost:8080/users/the_mighty_zork")) +} + +func (suite *FederatingProtocolTestSuite) TestPostInboxRequestBodyHook2() { + // the activity we're gonna use + activity := suite.testActivities["reply_to_turtle_for_zork"] + + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + + // setup transport controller with a no-op client so we don't make external calls + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(func(req *http.Request) (*http.Response, error) { + return nil, nil + }), suite.db, fedWorker) + // setup module being tested + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + // setup request + ctx := context.Background() + request := httptest.NewRequest(http.MethodPost, "http://localhost:8080/users/the_mighty_zork/inbox", nil) // the endpoint we're hitting + request.Header.Set("Signature", activity.SignatureHeader) + + // trigger the function being tested, and return the new context it creates + newContext, err := federator.PostInboxRequestBodyHook(ctx, request, activity.Activity) + suite.NoError(err) + suite.NotNil(newContext) + + involvedIRIsI := newContext.Value(ap.ContextOtherInvolvedIRIs) + involvedIRIs, ok := involvedIRIsI.([]*url.URL) + if !ok { + suite.FailNow("couldn't get involved IRIs from context") + } + + suite.Len(involvedIRIs, 2) + suite.Contains(involvedIRIs, testrig.URLMustParse("http://localhost:8080/users/1happyturtle")) + suite.Contains(involvedIRIs, testrig.URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")) +} + +func (suite *FederatingProtocolTestSuite) TestPostInboxRequestBodyHook3() { + // the activity we're gonna use + activity := suite.testActivities["reply_to_turtle_for_turtle"] + + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + + // setup transport controller with a no-op client so we don't make external calls + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(func(req *http.Request) (*http.Response, error) { + return nil, nil + }), suite.db, fedWorker) + // setup module being tested + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + // setup request + ctx := context.Background() + request := httptest.NewRequest(http.MethodPost, "http://localhost:8080/users/1happyturtle/inbox", nil) // the endpoint we're hitting + request.Header.Set("Signature", activity.SignatureHeader) + + // trigger the function being tested, and return the new context it creates + newContext, err := federator.PostInboxRequestBodyHook(ctx, request, activity.Activity) + suite.NoError(err) + suite.NotNil(newContext) + + involvedIRIsI := newContext.Value(ap.ContextOtherInvolvedIRIs) + involvedIRIs, ok := involvedIRIsI.([]*url.URL) + if !ok { + suite.FailNow("couldn't get involved IRIs from context") + } + + suite.Len(involvedIRIs, 2) + suite.Contains(involvedIRIs, testrig.URLMustParse("http://localhost:8080/users/1happyturtle")) + suite.Contains(involvedIRIs, testrig.URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")) } func (suite *FederatingProtocolTestSuite) TestAuthenticatePostInbox() { @@ -97,8 +165,7 @@ func (suite *FederatingProtocolTestSuite) TestAuthenticatePostInbox() { // by the time AuthenticatePostInbox is called, PostInboxRequestBodyHook should have already been called, // which should have set the account and username onto the request. We can replicate that behavior here: ctxWithAccount := context.WithValue(ctx, ap.ContextReceivingAccount, inboxAccount) - ctxWithActivity := context.WithValue(ctxWithAccount, ap.ContextActivity, activity) - ctxWithVerifier := context.WithValue(ctxWithActivity, ap.ContextRequestingPublicKeyVerifier, verifier) + ctxWithVerifier := context.WithValue(ctxWithAccount, ap.ContextRequestingPublicKeyVerifier, verifier) ctxWithSignature := context.WithValue(ctxWithVerifier, ap.ContextRequestingPublicKeySignature, activity.SignatureHeader) // we can pass this recorder as a writer and read it back after @@ -117,6 +184,125 @@ func (suite *FederatingProtocolTestSuite) TestAuthenticatePostInbox() { suite.Equal(sendingAccount.Username, requestingAccount.Username) } +func (suite *FederatingProtocolTestSuite) TestBlocked1() { + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db, fedWorker) + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + sendingAccount := suite.testAccounts["remote_account_1"] + inboxAccount := suite.testAccounts["local_account_1"] + otherInvolvedIRIs := []*url.URL{} + actorIRIs := []*url.URL{ + testrig.URLMustParse(sendingAccount.URI), + } + + ctx := context.Background() + ctxWithReceivingAccount := context.WithValue(ctx, ap.ContextReceivingAccount, inboxAccount) + ctxWithRequestingAccount := context.WithValue(ctxWithReceivingAccount, ap.ContextRequestingAccount, sendingAccount) + ctxWithOtherInvolvedIRIs := context.WithValue(ctxWithRequestingAccount, ap.ContextOtherInvolvedIRIs, otherInvolvedIRIs) + + blocked, err := federator.Blocked(ctxWithOtherInvolvedIRIs, actorIRIs) + suite.NoError(err) + suite.False(blocked) +} + +func (suite *FederatingProtocolTestSuite) TestBlocked2() { + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db, fedWorker) + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + sendingAccount := suite.testAccounts["remote_account_1"] + inboxAccount := suite.testAccounts["local_account_1"] + otherInvolvedIRIs := []*url.URL{} + actorIRIs := []*url.URL{ + testrig.URLMustParse(sendingAccount.URI), + } + + ctx := context.Background() + ctxWithReceivingAccount := context.WithValue(ctx, ap.ContextReceivingAccount, inboxAccount) + ctxWithRequestingAccount := context.WithValue(ctxWithReceivingAccount, ap.ContextRequestingAccount, sendingAccount) + ctxWithOtherInvolvedIRIs := context.WithValue(ctxWithRequestingAccount, ap.ContextOtherInvolvedIRIs, otherInvolvedIRIs) + + // insert a block from inboxAccount targeting sendingAccount + if err := suite.db.Put(context.Background(), >smodel.Block{ + ID: "01G3KBEMJD4VQ2D615MPV7KTRD", + URI: "whatever", + AccountID: inboxAccount.ID, + TargetAccountID: sendingAccount.ID, + }); err != nil { + suite.Fail(err.Error()) + } + + // request should be blocked now + blocked, err := federator.Blocked(ctxWithOtherInvolvedIRIs, actorIRIs) + suite.NoError(err) + suite.True(blocked) +} + +func (suite *FederatingProtocolTestSuite) TestBlocked3() { + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db, fedWorker) + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + sendingAccount := suite.testAccounts["remote_account_1"] + inboxAccount := suite.testAccounts["local_account_1"] + ccedAccount := suite.testAccounts["remote_account_2"] + + otherInvolvedIRIs := []*url.URL{ + testrig.URLMustParse(ccedAccount.URI), + } + actorIRIs := []*url.URL{ + testrig.URLMustParse(sendingAccount.URI), + } + + ctx := context.Background() + ctxWithReceivingAccount := context.WithValue(ctx, ap.ContextReceivingAccount, inboxAccount) + ctxWithRequestingAccount := context.WithValue(ctxWithReceivingAccount, ap.ContextRequestingAccount, sendingAccount) + ctxWithOtherInvolvedIRIs := context.WithValue(ctxWithRequestingAccount, ap.ContextOtherInvolvedIRIs, otherInvolvedIRIs) + + // insert a block from inboxAccount targeting CCed account + if err := suite.db.Put(context.Background(), >smodel.Block{ + ID: "01G3KBEMJD4VQ2D615MPV7KTRD", + URI: "whatever", + AccountID: inboxAccount.ID, + TargetAccountID: ccedAccount.ID, + }); err != nil { + suite.Fail(err.Error()) + } + + blocked, err := federator.Blocked(ctxWithOtherInvolvedIRIs, actorIRIs) + suite.NoError(err) + suite.True(blocked) +} + +func (suite *FederatingProtocolTestSuite) TestBlocked4() { + fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1) + tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db, fedWorker) + federator := federation.NewFederator(suite.db, testrig.NewTestFederatingDB(suite.db, fedWorker), tc, suite.tc, testrig.NewTestMediaManager(suite.db, suite.storage)) + + sendingAccount := suite.testAccounts["remote_account_1"] + inboxAccount := suite.testAccounts["local_account_1"] + repliedStatus := suite.testStatuses["local_account_2_status_1"] + + otherInvolvedIRIs := []*url.URL{ + testrig.URLMustParse(repliedStatus.URI), // this status is involved because the hypothetical activity is a reply to this status + } + actorIRIs := []*url.URL{ + testrig.URLMustParse(sendingAccount.URI), + } + + ctx := context.Background() + ctxWithReceivingAccount := context.WithValue(ctx, ap.ContextReceivingAccount, inboxAccount) + ctxWithRequestingAccount := context.WithValue(ctxWithReceivingAccount, ap.ContextRequestingAccount, sendingAccount) + ctxWithOtherInvolvedIRIs := context.WithValue(ctxWithRequestingAccount, ap.ContextOtherInvolvedIRIs, otherInvolvedIRIs) + + // local account 2 (replied status account) blocks sending account already so we don't need to add a block here + + blocked, err := federator.Blocked(ctxWithOtherInvolvedIRIs, actorIRIs) + suite.NoError(err) + suite.True(blocked) +} + func TestFederatingProtocolTestSuite(t *testing.T) { suite.Run(t, new(FederatingProtocolTestSuite)) } |