mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 04:02:26 -05:00 
			
		
		
		
	* love like winter! wohoah, wohoah * domain allow side effects * tests! logging! unallow! * document federation modes * linty linterson * test * further adventures in documentation * finish up domain block documentation (i think) * change wording a wee little bit * docs, example * consolidate shared domainPermission code * call mode once * fetch federation mode within domain blocked func * read domain perm import in streaming manner * don't use pointer to slice for domain perms * don't bother copying blocks + allows before deleting * admonish! * change wording just a scooch * update docs
		
			
				
	
	
		
			280 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			280 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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 <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| package admin_test
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/stretchr/testify/suite"
 | |
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
 | |
| 	"github.com/superseriousbusiness/gotosocial/internal/config"
 | |
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
 | |
| 	"github.com/superseriousbusiness/gotosocial/testrig"
 | |
| )
 | |
| 
 | |
| type DomainBlockTestSuite struct {
 | |
| 	AdminStandardTestSuite
 | |
| }
 | |
| 
 | |
| type domainPermAction struct {
 | |
| 	// 'create' or 'delete'
 | |
| 	// the domain permission.
 | |
| 	createOrDelete string
 | |
| 
 | |
| 	// Type of permission
 | |
| 	// to create or delete.
 | |
| 	permissionType gtsmodel.DomainPermissionType
 | |
| 
 | |
| 	// Domain to target
 | |
| 	// with the permission.
 | |
| 	domain string
 | |
| 
 | |
| 	// Expected result of this
 | |
| 	// permission action on each
 | |
| 	// account on the target domain.
 | |
| 	// Eg., suite.Zero(account.SuspendedAt)
 | |
| 	expected func(*gtsmodel.Account) bool
 | |
| }
 | |
| 
 | |
| type domainPermTest struct {
 | |
| 	// Federation mode under which to
 | |
| 	// run this test. This is important
 | |
| 	// because it may effect which side
 | |
| 	// effects are taken, if any.
 | |
| 	instanceFederationMode string
 | |
| 
 | |
| 	// Series of actions to run as part
 | |
| 	// of this test. After each action,
 | |
| 	// expected will be called. This
 | |
| 	// allows testers to run multiple
 | |
| 	// actions in a row and check that
 | |
| 	// the results after each action are
 | |
| 	// what they expected, in light of
 | |
| 	// previous actions.
 | |
| 	actions []domainPermAction
 | |
| }
 | |
| 
 | |
| // run a domainPermTest by running each of
 | |
| // its actions in turn and checking results.
 | |
| func (suite *DomainBlockTestSuite) runDomainPermTest(t domainPermTest) {
 | |
| 	config.SetInstanceFederationMode(t.instanceFederationMode)
 | |
| 
 | |
| 	for _, action := range t.actions {
 | |
| 		// Run the desired action.
 | |
| 		var actionID string
 | |
| 		switch action.createOrDelete {
 | |
| 		case "create":
 | |
| 			_, actionID = suite.createDomainPerm(action.permissionType, action.domain)
 | |
| 		case "delete":
 | |
| 			_, actionID = suite.deleteDomainPerm(action.permissionType, action.domain)
 | |
| 		default:
 | |
| 			panic("createOrDelete was not 'create' or 'delete'")
 | |
| 		}
 | |
| 
 | |
| 		// Let the action finish.
 | |
| 		suite.awaitAction(actionID)
 | |
| 
 | |
| 		// Check expected results
 | |
| 		// against each account.
 | |
| 		accounts, err := suite.db.GetInstanceAccounts(
 | |
| 			context.Background(),
 | |
| 			action.domain,
 | |
| 			"", 0,
 | |
| 		)
 | |
| 		if err != nil {
 | |
| 			suite.FailNow("", "error getting instance accounts for %s: %v", action.domain, err)
 | |
| 		}
 | |
| 
 | |
| 		for _, account := range accounts {
 | |
| 			if !action.expected(account) {
 | |
| 				suite.T().FailNow()
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // create given permissionType with default values.
 | |
| func (suite *DomainBlockTestSuite) createDomainPerm(
 | |
| 	permissionType gtsmodel.DomainPermissionType,
 | |
| 	domain string,
 | |
| ) (*apimodel.DomainPermission, string) {
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionCreate(
 | |
| 		ctx,
 | |
| 		permissionType,
 | |
| 		suite.testAccounts["admin_account"],
 | |
| 		domain,
 | |
| 		false,
 | |
| 		"",
 | |
| 		"",
 | |
| 		"",
 | |
| 	)
 | |
| 	suite.NoError(errWithCode)
 | |
| 	suite.NotNil(apiPerm)
 | |
| 	suite.NotEmpty(actionID)
 | |
| 
 | |
| 	return apiPerm, actionID
 | |
| }
 | |
| 
 | |
| // delete given permission type.
 | |
| func (suite *DomainBlockTestSuite) deleteDomainPerm(
 | |
| 	permissionType gtsmodel.DomainPermissionType,
 | |
| 	domain string,
 | |
| ) (*apimodel.DomainPermission, string) {
 | |
| 	var (
 | |
| 		ctx              = context.Background()
 | |
| 		domainPermission gtsmodel.DomainPermission
 | |
| 	)
 | |
| 
 | |
| 	// To delete the permission,
 | |
| 	// first get it from the db.
 | |
| 	switch permissionType {
 | |
| 	case gtsmodel.DomainPermissionBlock:
 | |
| 		domainPermission, _ = suite.db.GetDomainBlock(ctx, domain)
 | |
| 	case gtsmodel.DomainPermissionAllow:
 | |
| 		domainPermission, _ = suite.db.GetDomainAllow(ctx, domain)
 | |
| 	default:
 | |
| 		panic("unrecognized permission type")
 | |
| 	}
 | |
| 
 | |
| 	if domainPermission == nil {
 | |
| 		suite.FailNow("domain permission was nil")
 | |
| 	}
 | |
| 
 | |
| 	// Now use the ID to delete it.
 | |
| 	apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionDelete(
 | |
| 		ctx,
 | |
| 		permissionType,
 | |
| 		suite.testAccounts["admin_account"],
 | |
| 		domainPermission.GetID(),
 | |
| 	)
 | |
| 	suite.NoError(errWithCode)
 | |
| 	suite.NotNil(apiPerm)
 | |
| 	suite.NotEmpty(actionID)
 | |
| 
 | |
| 	return apiPerm, actionID
 | |
| }
 | |
| 
 | |
| // waits for given actionID to be completed.
 | |
| func (suite *DomainBlockTestSuite) awaitAction(actionID string) {
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	if !testrig.WaitFor(func() bool {
 | |
| 		return suite.adminProcessor.Actions().TotalRunning() == 0
 | |
| 	}) {
 | |
| 		suite.FailNow("timed out waiting for admin action(s) to finish")
 | |
| 	}
 | |
| 
 | |
| 	// Ensure action marked as
 | |
| 	// completed in the database.
 | |
| 	adminAction, err := suite.db.GetAdminAction(ctx, actionID)
 | |
| 	if err != nil {
 | |
| 		suite.FailNow(err.Error())
 | |
| 	}
 | |
| 
 | |
| 	suite.NotZero(adminAction.CompletedAt)
 | |
| 	suite.Empty(adminAction.Errors)
 | |
| }
 | |
| 
 | |
| func (suite *DomainBlockTestSuite) TestBlockAndUnblockDomain() {
 | |
| 	const domain = "fossbros-anonymous.io"
 | |
| 
 | |
| 	suite.runDomainPermTest(domainPermTest{
 | |
| 		instanceFederationMode: config.InstanceFederationModeBlocklist,
 | |
| 		actions: []domainPermAction{
 | |
| 			{
 | |
| 				createOrDelete: "create",
 | |
| 				permissionType: gtsmodel.DomainPermissionBlock,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Domain was blocked, so each
 | |
| 					// account should now be suspended.
 | |
| 					return suite.NotZero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 			{
 | |
| 				createOrDelete: "delete",
 | |
| 				permissionType: gtsmodel.DomainPermissionBlock,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Domain was unblocked, so each
 | |
| 					// account should now be unsuspended.
 | |
| 					return suite.Zero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
 | |
| 	const domain = "fossbros-anonymous.io"
 | |
| 
 | |
| 	suite.runDomainPermTest(domainPermTest{
 | |
| 		instanceFederationMode: config.InstanceFederationModeBlocklist,
 | |
| 		actions: []domainPermAction{
 | |
| 			{
 | |
| 				createOrDelete: "create",
 | |
| 				permissionType: gtsmodel.DomainPermissionBlock,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Domain was blocked, so each
 | |
| 					// account should now be suspended.
 | |
| 					return suite.NotZero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 			{
 | |
| 				createOrDelete: "create",
 | |
| 				permissionType: gtsmodel.DomainPermissionAllow,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Domain was explicitly allowed, so each
 | |
| 					// account should now be unsuspended, since
 | |
| 					// the allow supercedes the block.
 | |
| 					return suite.Zero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 			{
 | |
| 				createOrDelete: "delete",
 | |
| 				permissionType: gtsmodel.DomainPermissionAllow,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Deleting the allow now, while there's
 | |
| 					// still a block in place, should cause
 | |
| 					// the block to take effect again.
 | |
| 					return suite.NotZero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 			{
 | |
| 				createOrDelete: "delete",
 | |
| 				permissionType: gtsmodel.DomainPermissionBlock,
 | |
| 				domain:         domain,
 | |
| 				expected: func(account *gtsmodel.Account) bool {
 | |
| 					// Deleting the block now should
 | |
| 					// unsuspend the accounts again.
 | |
| 					return suite.Zero(account.SuspendedAt)
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func TestDomainBlockTestSuite(t *testing.T) {
 | |
| 	suite.Run(t, new(DomainBlockTestSuite))
 | |
| }
 |