Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unblock fix #247

Merged
merged 8 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -469,17 +469,11 @@ github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/uptrace/bun v1.0.5/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun v1.0.6 h1:o9eMq5ePGBXtxbK3SIreOCRr+rIBQzvJH+/s98kYcVM=
github.com/uptrace/bun v1.0.6/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun v1.0.8/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun v1.0.9-0.20210922104131-34c982b23581 h1:W8SAI7irrKSZ3t9MzFwehUyEd6f8ajOprqSzCxHFcxo=
github.com/uptrace/bun v1.0.9-0.20210922104131-34c982b23581/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun/dialect/pgdialect v1.0.5 h1:mq694/aMvs7GwuTar9NIlCLQt/2u4xsF0QMP4I24yHA=
github.com/uptrace/bun/dialect/pgdialect v1.0.5/go.mod h1:MKWjO0PC20ris2oJ3dd6mI/762x24Cjwh8XmbqUhM8A=
github.com/uptrace/bun/dialect/pgdialect v1.0.9-0.20210922104131-34c982b23581 h1:3r8Td1Y3I51f9LYcC/3EuQT8zKuCh+OWiQQ8FVHK4Pg=
github.com/uptrace/bun/dialect/pgdialect v1.0.9-0.20210922104131-34c982b23581/go.mod h1:HEGRgyS68SiHcKhFa9LXcDN+KEWo1I4VplvunL0Oi4o=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5 h1:6cIj31YVJr4vvA15C2v76soXL+7WtjFdV6WraApc3r0=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5/go.mod h1:NW2Gctc9ooQXGSD4kYSac2aiF49lo8YJ3ZAr93lH2p8=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.9-0.20210922104131-34c982b23581 h1:Yfbbo8EQffFLL7EEBq2yUirSg3b7NID4sgRGdNlIJa0=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.9-0.20210922104131-34c982b23581/go.mod h1:v1rNdAcJdw8AgD4x4OAJFIRFA9+sANoXK7u21H9Wvkg=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
Expand Down
4 changes: 2 additions & 2 deletions internal/api/s2s/user/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ var ActivityPubAcceptHeaders = []string{
`application/ld+json; profile="https://www.w3.org/ns/activitystreams"`,
}

// populateContext transfers the signature verifier and signature from the gin context to the request context
func populateContext(c *gin.Context) context.Context {
// transferContext transfers the signature verifier and signature from the gin context to the request context
func transferContext(c *gin.Context) context.Context {
ctx := c.Request.Context()

verifier, signed := c.Get(string(util.APRequestingPublicKeyVerifier))
Expand Down
2 changes: 1 addition & 1 deletion internal/api/s2s/user/followers.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (m *Module) FollowersGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)

ctx := populateContext(c)
ctx := transferContext(c)

followers, errWithCode := m.processor.GetFediFollowers(ctx, requestedUsername, c.Request.URL)
if errWithCode != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/api/s2s/user/following.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (m *Module) FollowingGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)

ctx := populateContext(c)
ctx := transferContext(c)

following, errWithCode := m.processor.GetFediFollowing(ctx, requestedUsername, c.Request.URL)
if errWithCode != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/api/s2s/user/inboxpost.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ func (m *Module) InboxPOSTHandler(c *gin.Context) {
return
}

ctx := populateContext(c)
ctx := transferContext(c)

posted, err := m.processor.InboxPost(ctx, c.Writer, c.Request)
if err != nil {
if withCode, ok := err.(gtserror.WithCode); ok {
l.Debug(withCode.Error())
l.Debugf("InboxPOSTHandler: %s", withCode.Error())
c.JSON(withCode.Code(), withCode.Safe())
return
}
Expand All @@ -55,7 +55,7 @@ func (m *Module) InboxPOSTHandler(c *gin.Context) {
}

if !posted {
l.Debugf("request could not be handled as an AP request; headers were: %+v", c.Request.Header)
l.Debugf("InboxPOSTHandler: request could not be handled as an AP request; headers were: %+v", c.Request.Header)
c.JSON(http.StatusBadRequest, gin.H{"error": "unable to process request"})
}
}
228 changes: 228 additions & 0 deletions internal/api/s2s/user/inboxpost_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

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 user_test

import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/gin-gonic/gin"
"github.com/go-fed/activity/streams"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/id"
"github.com/superseriousbusiness/gotosocial/testrig"
)

type InboxPostTestSuite struct {
UserStandardTestSuite
}

func (suite *InboxPostTestSuite) TestPostBlock() {
blockingAccount := suite.testAccounts["remote_account_1"]
blockedAccount := suite.testAccounts["local_account_1"]
blockURI := testrig.URLMustParse("http://fossbros-anonymous.io/users/foss_satan/blocks/01FG9C441MCTW3R2W117V2PQK3")

block := streams.NewActivityStreamsBlock()

// set the actor property to the block-ing account's URI
actorProp := streams.NewActivityStreamsActorProperty()
actorIRI := testrig.URLMustParse(blockingAccount.URI)
actorProp.AppendIRI(actorIRI)
block.SetActivityStreamsActor(actorProp)

// set the ID property to the blocks's URI
idProp := streams.NewJSONLDIdProperty()
idProp.Set(blockURI)
block.SetJSONLDId(idProp)

// set the object property to the target account's URI
objectProp := streams.NewActivityStreamsObjectProperty()
targetIRI := testrig.URLMustParse(blockedAccount.URI)
objectProp.AppendIRI(targetIRI)
block.SetActivityStreamsObject(objectProp)

// set the TO property to the target account's IRI
toProp := streams.NewActivityStreamsToProperty()
toIRI := testrig.URLMustParse(blockedAccount.URI)
toProp.AppendIRI(toIRI)
block.SetActivityStreamsTo(toProp)

targetURI := testrig.URLMustParse(blockedAccount.InboxURI)

signature, digestHeader, dateHeader := testrig.GetSignatureForActivity(block, blockingAccount.PublicKeyURI, blockingAccount.PrivateKey, targetURI)
bodyI, err := streams.Serialize(block)
suite.NoError(err)

bodyJson, err := json.Marshal(bodyI)
suite.NoError(err)
body := bytes.NewReader(bodyJson)

tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db)
federator := testrig.NewTestFederator(suite.db, tc, suite.storage)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator)
userModule := user.New(suite.config, processor, suite.log).(*user.Module)

// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)
ctx.Request.Header.Set("Digest", digestHeader)
ctx.Request.Header.Set("Content-Type", "application/activity+json")

// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)

// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Value: blockedAccount.Username,
},
}

// trigger the function being tested
userModule.InboxPOSTHandler(ctx)

result := recorder.Result()
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
suite.NoError(err)
suite.Empty(b)

// there should be a block in the database now between the accounts
dbBlock, err := suite.db.GetBlock(context.Background(), blockingAccount.ID, blockedAccount.ID)
suite.NoError(err)
suite.NotNil(dbBlock)
suite.WithinDuration(time.Now(), dbBlock.CreatedAt, 30*time.Second)
suite.WithinDuration(time.Now(), dbBlock.UpdatedAt, 30*time.Second)
suite.Equal("http://fossbros-anonymous.io/users/foss_satan/blocks/01FG9C441MCTW3R2W117V2PQK3", dbBlock.URI)
}

// TestPostUnblock verifies that a remote account with a block targeting one of our instance users should be able to undo that block.
func (suite *InboxPostTestSuite) TestPostUnblock() {
blockingAccount := suite.testAccounts["remote_account_1"]
blockedAccount := suite.testAccounts["local_account_1"]

// first put a block in the database so we have something to undo
blockURI := "http://fossbros-anonymous.io/users/foss_satan/blocks/01FG9C441MCTW3R2W117V2PQK3"
dbBlockID, err := id.NewRandomULID()
suite.NoError(err)

dbBlock := &gtsmodel.Block{
ID: dbBlockID,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
URI: blockURI,
AccountID: blockingAccount.ID,
TargetAccountID: blockedAccount.ID,
}

err = suite.db.Put(context.Background(), dbBlock)
suite.NoError(err)

asBlock, err := suite.tc.BlockToAS(context.Background(), dbBlock)
suite.NoError(err)

targetAccountURI := testrig.URLMustParse(blockedAccount.URI)

// create an Undo and set the appropriate actor on it
undo := streams.NewActivityStreamsUndo()
undo.SetActivityStreamsActor(asBlock.GetActivityStreamsActor())

// Set the block as the 'object' property.
undoObject := streams.NewActivityStreamsObjectProperty()
undoObject.AppendActivityStreamsBlock(asBlock)
undo.SetActivityStreamsObject(undoObject)

// Set the To of the undo as the target of the block
undoTo := streams.NewActivityStreamsToProperty()
undoTo.AppendIRI(targetAccountURI)
undo.SetActivityStreamsTo(undoTo)

undoID := streams.NewJSONLDIdProperty()
undoID.SetIRI(testrig.URLMustParse("http://fossbros-anonymous.io/72cc96a3-f742-4daf-b9f5-3407667260c5"))
undo.SetJSONLDId(undoID)

targetURI := testrig.URLMustParse(blockedAccount.InboxURI)

signature, digestHeader, dateHeader := testrig.GetSignatureForActivity(undo, blockingAccount.PublicKeyURI, blockingAccount.PrivateKey, targetURI)
bodyI, err := streams.Serialize(undo)
suite.NoError(err)

bodyJson, err := json.Marshal(bodyI)
suite.NoError(err)
body := bytes.NewReader(bodyJson)

tc := testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil), suite.db)
federator := testrig.NewTestFederator(suite.db, tc, suite.storage)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator)
userModule := user.New(suite.config, processor, suite.log).(*user.Module)

// setup request
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Request = httptest.NewRequest(http.MethodPost, targetURI.String(), body) // the endpoint we're hitting
ctx.Request.Header.Set("Signature", signature)
ctx.Request.Header.Set("Date", dateHeader)
ctx.Request.Header.Set("Digest", digestHeader)
ctx.Request.Header.Set("Content-Type", "application/activity+json")

// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)

// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Value: blockedAccount.Username,
},
}

// trigger the function being tested
userModule.InboxPOSTHandler(ctx)

result := recorder.Result()
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
suite.NoError(err)
suite.Empty(b)
suite.Equal(http.StatusOK, result.StatusCode)

// the block should be undone
block, err := suite.db.GetBlock(context.Background(), blockingAccount.ID, blockedAccount.ID)
suite.ErrorIs(err, db.ErrNoEntries)
suite.Nil(block)
}

func TestInboxPostTestSuite(t *testing.T) {
suite.Run(t, &InboxPostTestSuite{})
}
20 changes: 19 additions & 1 deletion internal/api/s2s/user/publickeyget.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

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 user

import (
Expand Down Expand Up @@ -33,7 +51,7 @@ func (m *Module) PublicKeyGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)

ctx := populateContext(c)
ctx := transferContext(c)

user, errWithCode := m.processor.GetFediUser(ctx, requestedUsername, c.Request.URL)
if errWithCode != nil {
Expand Down
20 changes: 19 additions & 1 deletion internal/api/s2s/user/repliesget.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

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 user

import (
Expand Down Expand Up @@ -121,7 +139,7 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
}
l.Tracef("negotiated format: %s", format)

ctx := populateContext(c)
ctx := transferContext(c)

replies, errWithCode := m.processor.GetFediStatusReplies(ctx, requestedUsername, requestedStatusID, page, onlyOtherAccounts, minID, c.Request.URL)
if errWithCode != nil {
Expand Down
18 changes: 18 additions & 0 deletions internal/api/s2s/user/repliesget_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
GoToSocial
Copyright (C) 2021 GoToSocial Authors [email protected]

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 user_test

import (
Expand Down
Loading