// GoToSocial // Copyright (C) GoToSocial Authors admin@gotosocial.org // SPDX-License-Identifier: AGPL-3.0-or-later // // 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 . package federatingdb_test import ( "encoding/json" "testing" "time" "github.com/stretchr/testify/suite" "github.com/superseriousbusiness/activity/streams" "github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/messages" ) type MoveTestSuite struct { FederatingDBTestSuite } func (suite *MoveTestSuite) move( receivingAcct *gtsmodel.Account, requestingAcct *gtsmodel.Account, moveStr string, ) error { ctx := createTestContext(receivingAcct, requestingAcct) rawMove := make(map[string]interface{}) if err := json.Unmarshal([]byte(moveStr), &rawMove); err != nil { suite.FailNow(err.Error()) } t, err := streams.ToType(ctx, rawMove) if err != nil { suite.FailNow(err.Error()) } move, ok := t.(vocab.ActivityStreamsMove) if !ok { suite.FailNow("", "couldn't cast %T to Move", t) } return suite.federatingDB.Move(ctx, move) } func (suite *MoveTestSuite) TestMove() { var ( receivingAcct = suite.testAccounts["local_account_1"] requestingAcct = suite.testAccounts["remote_account_1"] moveStr1 = `{ "@context": "https://www.w3.org/ns/activitystreams", "id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9", "actor": "http://fossbros-anonymous.io/users/foss_satan", "type": "Move", "object": "http://fossbros-anonymous.io/users/foss_satan", "target": "https://turnip.farm/users/turniplover6969", "to": "http://fossbros-anonymous.io/users/foss_satan/followers" }` ) // Trigger the move. suite.move(receivingAcct, requestingAcct, moveStr1) // Should be a message heading to the processor. var msg messages.FromFediAPI select { case msg = <-suite.fromFederator: // Fine. case <-time.After(5 * time.Second): suite.FailNow("", "timeout waiting for suite.fromFederator") } suite.Equal(ap.ObjectProfile, msg.APObjectType) suite.Equal(ap.ActivityMove, msg.APActivityType) // Stub Move should be on the message. move, ok := msg.GTSModel.(*gtsmodel.Move) if !ok { suite.FailNow("", "could not cast %T to *gtsmodel.Move", msg.GTSModel) } suite.Equal("http://fossbros-anonymous.io/users/foss_satan", move.OriginURI) suite.Equal("https://turnip.farm/users/turniplover6969", move.TargetURI) // Trigger the same move again. suite.move(receivingAcct, requestingAcct, moveStr1) // Should be a message heading to the processor // since this is just a straight up retry. select { case msg = <-suite.fromFederator: // Fine. case <-time.After(5 * time.Second): suite.FailNow("", "timeout waiting for suite.fromFederator") } suite.Equal(ap.ObjectProfile, msg.APObjectType) suite.Equal(ap.ActivityMove, msg.APActivityType) // Same as the first Move, but with a different ID. moveStr2 := `{ "@context": "https://www.w3.org/ns/activitystreams", "id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9XWDD25CKXHW82MYD1GDAR", "actor": "http://fossbros-anonymous.io/users/foss_satan", "type": "Move", "object": "http://fossbros-anonymous.io/users/foss_satan", "target": "https://turnip.farm/users/turniplover6969", "to": "http://fossbros-anonymous.io/users/foss_satan/followers" }` // Trigger the move. suite.move(receivingAcct, requestingAcct, moveStr2) // Should be a message heading to the processor // since this is just a retry with a different ID. select { case msg = <-suite.fromFederator: // Fine. case <-time.After(5 * time.Second): suite.FailNow("", "timeout waiting for suite.fromFederator") } suite.Equal(ap.ObjectProfile, msg.APObjectType) suite.Equal(ap.ActivityMove, msg.APActivityType) } func (suite *MoveTestSuite) TestBadMoves() { var ( receivingAcct = suite.testAccounts["local_account_1"] requestingAcct = suite.testAccounts["remote_account_1"] ) type testStruct struct { moveStr string err string } for _, t := range []testStruct{ { // Move signed by someone else. moveStr: `{ "@context": "https://www.w3.org/ns/activitystreams", "id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9", "actor": "http://fossbros-anonymous.io/users/someone_else", "type": "Move", "object": "http://fossbros-anonymous.io/users/foss_satan", "target": "https://turnip.farm/users/turniplover6969", "to": "http://fossbros-anonymous.io/users/foss_satan/followers" }`, err: "Move was signed by http://fossbros-anonymous.io/users/foss_satan but actor was http://fossbros-anonymous.io/users/someone_else", }, { // Actor and object not the same. moveStr: `{ "@context": "https://www.w3.org/ns/activitystreams", "id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9", "actor": "http://fossbros-anonymous.io/users/foss_satan", "type": "Move", "object": "http://fossbros-anonymous.io/users/someone_else", "target": "https://turnip.farm/users/turniplover6969", "to": "http://fossbros-anonymous.io/users/foss_satan/followers" }`, err: "Move was signed by http://fossbros-anonymous.io/users/foss_satan but object was http://fossbros-anonymous.io/users/someone_else", }, { // Object and target the same. moveStr: `{ "@context": "https://www.w3.org/ns/activitystreams", "id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9", "actor": "http://fossbros-anonymous.io/users/foss_satan", "type": "Move", "object": "http://fossbros-anonymous.io/users/foss_satan", "target": "http://fossbros-anonymous.io/users/foss_satan", "to": "http://fossbros-anonymous.io/users/foss_satan/followers" }`, err: "Move target and origin were the same (http://fossbros-anonymous.io/users/foss_satan)", }, } { // Trigger the move. err := suite.move(receivingAcct, requestingAcct, t.moveStr) if t.err != "" { suite.EqualError(err, t.err) } } } func TestMoveTestSuite(t *testing.T) { suite.Run(t, &MoveTestSuite{}) }