From 4a69651a7c7945b11760d9ca82d9945834f01f73 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Mon, 4 Jul 2022 15:41:20 +0200 Subject: [PATCH] [bugfix] Visibility fixes (#687) * test self boost * only CC to public when necessary --- .../api/client/status/statusboost_test.go | 116 ++++++++++++++---- internal/typeutils/internaltoas.go | 18 +-- internal/typeutils/internaltoas_test.go | 38 +++++- 3 files changed, 133 insertions(+), 39 deletions(-) diff --git a/internal/api/client/status/statusboost_test.go b/internal/api/client/status/statusboost_test.go index e33b582e8..c8d33f0f8 100644 --- a/internal/api/client/status/statusboost_test.go +++ b/internal/api/client/status/statusboost_test.go @@ -26,7 +26,6 @@ import ( "testing" "github.com/gin-gonic/gin" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/superseriousbusiness/gotosocial/internal/api/client/status" "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -72,36 +71,101 @@ func (suite *StatusBoostTestSuite) TestPostBoost() { result := recorder.Result() defer result.Body.Close() b, err := ioutil.ReadAll(result.Body) - assert.NoError(suite.T(), err) + suite.NoError(err) statusReply := &model.Status{} err = json.Unmarshal(b, statusReply) - assert.NoError(suite.T(), err) + suite.NoError(err) - assert.False(suite.T(), statusReply.Sensitive) - assert.Equal(suite.T(), model.VisibilityPublic, statusReply.Visibility) + suite.False(statusReply.Sensitive) + suite.Equal(model.VisibilityPublic, statusReply.Visibility) - assert.Equal(suite.T(), targetStatus.ContentWarning, statusReply.SpoilerText) - assert.Equal(suite.T(), targetStatus.Content, statusReply.Content) - assert.Equal(suite.T(), "the_mighty_zork", statusReply.Account.Username) - assert.Len(suite.T(), statusReply.MediaAttachments, 0) - assert.Len(suite.T(), statusReply.Mentions, 0) - assert.Len(suite.T(), statusReply.Emojis, 0) - assert.Len(suite.T(), statusReply.Tags, 0) + suite.Equal(targetStatus.ContentWarning, statusReply.SpoilerText) + suite.Equal(targetStatus.Content, statusReply.Content) + suite.Equal("the_mighty_zork", statusReply.Account.Username) + suite.Len(statusReply.MediaAttachments, 0) + suite.Len(statusReply.Mentions, 0) + suite.Len(statusReply.Emojis, 0) + suite.Len(statusReply.Tags, 0) - assert.NotNil(suite.T(), statusReply.Application) - assert.Equal(suite.T(), "really cool gts application", statusReply.Application.Name) + suite.NotNil(statusReply.Application) + suite.Equal("really cool gts application", statusReply.Application.Name) - assert.NotNil(suite.T(), statusReply.Reblog) - assert.Equal(suite.T(), 1, statusReply.Reblog.ReblogsCount) - assert.Equal(suite.T(), 1, statusReply.Reblog.FavouritesCount) - assert.Equal(suite.T(), targetStatus.Content, statusReply.Reblog.Content) - assert.Equal(suite.T(), targetStatus.ContentWarning, statusReply.Reblog.SpoilerText) - assert.Equal(suite.T(), targetStatus.AccountID, statusReply.Reblog.Account.ID) - assert.Len(suite.T(), statusReply.Reblog.MediaAttachments, 1) - assert.Len(suite.T(), statusReply.Reblog.Tags, 1) - assert.Len(suite.T(), statusReply.Reblog.Emojis, 1) - assert.Equal(suite.T(), "superseriousbusiness", statusReply.Reblog.Application.Name) + suite.NotNil(statusReply.Reblog) + suite.Equal(1, statusReply.Reblog.ReblogsCount) + suite.Equal(1, statusReply.Reblog.FavouritesCount) + suite.Equal(targetStatus.Content, statusReply.Reblog.Content) + suite.Equal(targetStatus.ContentWarning, statusReply.Reblog.SpoilerText) + suite.Equal(targetStatus.AccountID, statusReply.Reblog.Account.ID) + suite.Len(statusReply.Reblog.MediaAttachments, 1) + suite.Len(statusReply.Reblog.Tags, 1) + suite.Len(statusReply.Reblog.Emojis, 1) + suite.Equal("superseriousbusiness", statusReply.Reblog.Application.Name) +} + +func (suite *StatusBoostTestSuite) TestPostBoostOwnFollowersOnly() { + t := suite.testTokens["local_account_1"] + oauthToken := oauth.DBTokenToToken(t) + + testStatus := suite.testStatuses["local_account_1_status_5"] + testAccount := suite.testAccounts["local_account_1"] + testUser := suite.testUsers["local_account_1"] + + recorder := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(recorder) + ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"]) + ctx.Set(oauth.SessionAuthorizedToken, oauthToken) + ctx.Set(oauth.SessionAuthorizedUser, testUser) + ctx.Set(oauth.SessionAuthorizedAccount, testAccount) + ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(status.ReblogPath, ":id", testStatus.ID, 1)), nil) + ctx.Request.Header.Set("accept", "application/json") + + ctx.Params = gin.Params{ + gin.Param{ + Key: status.IDKey, + Value: testStatus.ID, + }, + } + + suite.statusModule.StatusBoostPOSTHandler(ctx) + + // check response + suite.EqualValues(http.StatusOK, recorder.Code) + + result := recorder.Result() + defer result.Body.Close() + b, err := ioutil.ReadAll(result.Body) + suite.NoError(err) + + responseStatus := &model.Status{} + err = json.Unmarshal(b, responseStatus) + suite.NoError(err) + + suite.False(responseStatus.Sensitive) + suite.Equal(suite.tc.VisToAPIVis(context.Background(), testStatus.Visibility), responseStatus.Visibility) + + suite.Equal(testStatus.ContentWarning, responseStatus.SpoilerText) + suite.Equal(testStatus.Content, responseStatus.Content) + suite.Equal("the_mighty_zork", responseStatus.Account.Username) + suite.Len(responseStatus.MediaAttachments, 0) + suite.Len(responseStatus.Mentions, 0) + suite.Len(responseStatus.Emojis, 0) + suite.Len(responseStatus.Tags, 0) + + suite.NotNil(responseStatus.Application) + suite.Equal("really cool gts application", responseStatus.Application.Name) + + suite.NotNil(responseStatus.Reblog) + suite.Equal(1, responseStatus.Reblog.ReblogsCount) + suite.Equal(0, responseStatus.Reblog.FavouritesCount) + suite.Equal(testStatus.Content, responseStatus.Reblog.Content) + suite.Equal(testStatus.ContentWarning, responseStatus.Reblog.SpoilerText) + suite.Equal(testStatus.AccountID, responseStatus.Reblog.Account.ID) + suite.Equal(suite.tc.VisToAPIVis(context.Background(), testStatus.Visibility), responseStatus.Reblog.Visibility) + suite.Empty(responseStatus.Reblog.MediaAttachments) + suite.Empty(responseStatus.Reblog.Tags) + suite.Empty(responseStatus.Reblog.Emojis) + suite.Equal("really cool gts application", responseStatus.Reblog.Application.Name) } // try to boost a status that's not boostable @@ -139,8 +203,8 @@ func (suite *StatusBoostTestSuite) TestPostUnboostable() { result := recorder.Result() defer result.Body.Close() b, err := ioutil.ReadAll(result.Body) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), `{"error":"Forbidden"}`, string(b)) + suite.NoError(err) + suite.Equal(`{"error":"Forbidden"}`, string(b)) } // try to boost a status that's not visible to the user diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index 81f4d9a31..2e6bd3091 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -815,19 +815,23 @@ func (c *converter) BoostToAS(ctx context.Context, boostWrapperStatus *gtsmodel. announce.SetActivityStreamsTo(toProp) // set the cc - boostedURI, err := url.Parse(boostedAccount.URI) + ccProp := streams.NewActivityStreamsCcProperty() + boostedAccountURI, err := url.Parse(boostedAccount.URI) if err != nil { return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", boostedAccount.URI, err) } + ccProp.AppendIRI(boostedAccountURI) - publicURI, err := url.Parse(pub.PublicActivityPubIRI) - if err != nil { - return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", pub.PublicActivityPubIRI, err) + // maybe CC it to public depending on the boosted status visibility + switch boostWrapperStatus.BoostOf.Visibility { + case gtsmodel.VisibilityPublic, gtsmodel.VisibilityUnlocked: + publicURI, err := url.Parse(pub.PublicActivityPubIRI) + if err != nil { + return nil, fmt.Errorf("BoostToAS: error parsing uri %s: %s", pub.PublicActivityPubIRI, err) + } + ccProp.AppendIRI(publicURI) } - ccProp := streams.NewActivityStreamsCcProperty() - ccProp.AppendIRI(boostedURI) - ccProp.AppendIRI(publicURI) announce.SetActivityStreamsCc(ccProp) return announce, nil diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go index 53403669e..7e7bd545e 100644 --- a/internal/typeutils/internaltoas_test.go +++ b/internal/typeutils/internaltoas_test.go @@ -24,9 +24,9 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "github.com/superseriousbusiness/activity/streams" + "github.com/superseriousbusiness/gotosocial/testrig" ) type InternalToASTestSuite struct { @@ -60,7 +60,7 @@ func (suite *InternalToASTestSuite) TestOutboxToASCollection() { suite.NoError(err) ser, err := streams.Serialize(collection) - assert.NoError(suite.T(), err) + suite.NoError(err) bytes, err := json.Marshal(ser) suite.NoError(err) @@ -86,7 +86,7 @@ func (suite *InternalToASTestSuite) TestStatusToAS() { suite.NoError(err) ser, err := streams.Serialize(asStatus) - assert.NoError(suite.T(), err) + suite.NoError(err) bytes, err := json.Marshal(ser) suite.NoError(err) @@ -105,7 +105,7 @@ func (suite *InternalToASTestSuite) TestStatusToASWithMentions() { suite.NoError(err) ser, err := streams.Serialize(asStatus) - assert.NoError(suite.T(), err) + suite.NoError(err) bytes, err := json.Marshal(ser) suite.NoError(err) @@ -122,7 +122,7 @@ func (suite *InternalToASTestSuite) TestStatusToASNotSensitive() { suite.NoError(err) ser, err := streams.Serialize(asStatus) - assert.NoError(suite.T(), err) + suite.NoError(err) bytes, err := json.Marshal(ser) suite.NoError(err) @@ -142,7 +142,7 @@ func (suite *InternalToASTestSuite) TestStatusesToASOutboxPage() { suite.NoError(err) ser, err := streams.Serialize(page) - assert.NoError(suite.T(), err) + suite.NoError(err) bytes, err := json.Marshal(ser) suite.NoError(err) @@ -184,6 +184,32 @@ func (suite *InternalToASTestSuite) TestStatusesToASOutboxPage() { suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:8080/users/admin/outbox?page=true","next":"http://localhost:8080/users/admin/outbox?page=true\u0026max_id=01F8MH75CBF9JFX4ZAD54N0W0R","orderedItems":[{"actor":"http://localhost:8080/users/admin","cc":"http://localhost:8080/users/admin/followers","id":"http://localhost:8080/users/admin/statuses/01F8MHAAY43M6RJ473VQFCVH37/activity","object":"http://localhost:8080/users/admin/statuses/01F8MHAAY43M6RJ473VQFCVH37","published":"2021-10-20T12:36:45Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Create"},{"actor":"http://localhost:8080/users/admin","cc":"http://localhost:8080/users/admin/followers","id":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R/activity","object":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R","published":"2021-10-20T11:36:45Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Create"}],"partOf":"http://localhost:8080/users/admin/outbox","prev":"http://localhost:8080/users/admin/outbox?page=true\u0026min_id=01F8MHAAY43M6RJ473VQFCVH37","type":"OrderedCollectionPage"}`, string(bytes)) } +func (suite *InternalToASTestSuite) TestSelfBoostFollowersOnlyToAS() { + ctx := context.Background() + + testStatus := suite.testStatuses["local_account_1_status_5"] + testAccount := suite.testAccounts["local_account_1"] + + boostWrapperStatus, err := suite.typeconverter.StatusToBoost(ctx, testStatus, testAccount) + suite.NoError(err) + suite.NotNil(boostWrapperStatus) + + boostWrapperStatus.ID = "01G74JJ1KS331G2JXHRMZCE0ER" + boostWrapperStatus.URI = "http://localhost:8080/users/the_mighty_zork/statuses/01G74JJ1KS331G2JXHRMZCE0ER" + boostWrapperStatus.CreatedAt = testrig.TimeMustParse("2022-06-09T13:12:00Z") + + asBoost, err := suite.typeconverter.BoostToAS(ctx, boostWrapperStatus, testAccount, testAccount) + suite.NoError(err) + + ser, err := streams.Serialize(asBoost) + suite.NoError(err) + + bytes, err := json.Marshal(ser) + suite.NoError(err) + + suite.Equal(`{"@context":"https://www.w3.org/ns/activitystreams","actor":"http://localhost:8080/users/the_mighty_zork","cc":"http://localhost:8080/users/the_mighty_zork","id":"http://localhost:8080/users/the_mighty_zork/statuses/01G74JJ1KS331G2JXHRMZCE0ER","object":"http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS","published":"2022-06-09T13:12:00Z","to":"http://localhost:8080/users/the_mighty_zork/followers","type":"Announce"}`, string(bytes)) +} + func TestInternalToASTestSuite(t *testing.T) { suite.Run(t, new(InternalToASTestSuite)) }