mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:42:24 -05:00 
			
		
		
		
	[feature] Serve bot accounts over AP as Service instead of Person (#3672)
* pepis * oopsie doopsie * bollocks
This commit is contained in:
		
					parent
					
						
							
								b42cb7a802
							
						
					
				
			
			
				commit
				
					
						9333bbc4d0
					
				
			
		
					 14 changed files with 315 additions and 175 deletions
				
			
		|  | @ -1,5 +1,13 @@ | ||||||
| # Actors and Actor Properties | # Actors and Actor Properties | ||||||
| 
 | 
 | ||||||
|  | ## `Service` vs `Person` actors | ||||||
|  | 
 | ||||||
|  | GoToSocial serves most accounts as the ActivityStreams `Person` type described [here](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person). | ||||||
|  | 
 | ||||||
|  | Accounts that users have selected to mark as bot accounts, however, will use the `Service` type described [here](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service). | ||||||
|  | 
 | ||||||
|  | This type distinction can be used by remote servers to distinguish between bot accounts and "regular" user accounts. | ||||||
|  | 
 | ||||||
| ## Inbox | ## Inbox | ||||||
| 
 | 
 | ||||||
| GoToSocial implements Inboxes for Actors following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#inbox). | GoToSocial implements Inboxes for Actors following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#inbox). | ||||||
|  |  | ||||||
|  | @ -17,6 +17,22 @@ | ||||||
| 
 | 
 | ||||||
| package ap | package ap | ||||||
| 
 | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/url" | ||||||
|  | 
 | ||||||
|  | 	"github.com/superseriousbusiness/activity/pub" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // PublicURI returns a fresh copy of the *url.URL version of the | ||||||
|  | // magic ActivityPub URI https://www.w3.org/ns/activitystreams#Public | ||||||
|  | func PublicURI() *url.URL { | ||||||
|  | 	publicURI, err := url.Parse(pub.PublicActivityPubIRI) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	return publicURI | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://www.w3.org/TR/activitystreams-vocabulary | // https://www.w3.org/TR/activitystreams-vocabulary | ||||||
| const ( | const ( | ||||||
| 	ActivityAccept          = "Accept"          // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept | 	ActivityAccept          = "Accept"          // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept | ||||||
|  |  | ||||||
|  | @ -24,7 +24,6 @@ import ( | ||||||
| 	"io" | 	"io" | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/suite" | 	"github.com/stretchr/testify/suite" | ||||||
| 	"github.com/superseriousbusiness/activity/pub" |  | ||||||
| 	"github.com/superseriousbusiness/activity/streams" | 	"github.com/superseriousbusiness/activity/streams" | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
|  | @ -111,7 +110,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote { | ||||||
| 
 | 
 | ||||||
| 	// Anyone can like. | 	// Anyone can like. | ||||||
| 	canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty() | 	canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty() | ||||||
| 	canLikeAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	canLikeAlwaysProp.AppendIRI(ap.PublicURI()) | ||||||
| 	canLike.SetGoToSocialAlways(canLikeAlwaysProp) | 	canLike.SetGoToSocialAlways(canLikeAlwaysProp) | ||||||
| 
 | 
 | ||||||
| 	// Empty approvalRequired. | 	// Empty approvalRequired. | ||||||
|  | @ -128,7 +127,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote { | ||||||
| 
 | 
 | ||||||
| 	// Anyone can reply. | 	// Anyone can reply. | ||||||
| 	canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty() | 	canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty() | ||||||
| 	canReplyAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	canReplyAlwaysProp.AppendIRI(ap.PublicURI()) | ||||||
| 	canReply.SetGoToSocialAlways(canReplyAlwaysProp) | 	canReply.SetGoToSocialAlways(canReplyAlwaysProp) | ||||||
| 
 | 
 | ||||||
| 	// Set empty approvalRequired. | 	// Set empty approvalRequired. | ||||||
|  | @ -151,7 +150,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote { | ||||||
| 
 | 
 | ||||||
| 	// Public requires approval to announce. | 	// Public requires approval to announce. | ||||||
| 	canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty() | 	canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty() | ||||||
| 	canAnnounceApprovalRequiredProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicURI()) | ||||||
| 	canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp) | 	canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp) | ||||||
| 
 | 
 | ||||||
| 	// Set canAnnounce on the policy. | 	// Set canAnnounce on the policy. | ||||||
|  | @ -266,7 +265,7 @@ func addressable1() ap.Addressable { | ||||||
| 	note := streams.NewActivityStreamsNote() | 	note := streams.NewActivityStreamsNote() | ||||||
| 
 | 
 | ||||||
| 	toProp := streams.NewActivityStreamsToProperty() | 	toProp := streams.NewActivityStreamsToProperty() | ||||||
| 	toProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	toProp.AppendIRI(ap.PublicURI()) | ||||||
| 
 | 
 | ||||||
| 	note.SetActivityStreamsTo(toProp) | 	note.SetActivityStreamsTo(toProp) | ||||||
| 
 | 
 | ||||||
|  | @ -288,7 +287,7 @@ func addressable2() ap.Addressable { | ||||||
| 	note.SetActivityStreamsTo(toProp) | 	note.SetActivityStreamsTo(toProp) | ||||||
| 
 | 
 | ||||||
| 	ccProp := streams.NewActivityStreamsCcProperty() | 	ccProp := streams.NewActivityStreamsCcProperty() | ||||||
| 	ccProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	ccProp.AppendIRI(ap.PublicURI()) | ||||||
| 
 | 
 | ||||||
| 	note.SetActivityStreamsCc(ccProp) | 	note.SetActivityStreamsCc(ccProp) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -188,6 +188,7 @@ type Accountable interface { | ||||||
| 	WithTag | 	WithTag | ||||||
| 	WithPublished | 	WithPublished | ||||||
| 	WithUpdated | 	WithUpdated | ||||||
|  | 	WithImage | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Statusable represents the minimum activitypub interface for representing a 'status'. | // Statusable represents the minimum activitypub interface for representing a 'status'. | ||||||
|  | @ -439,6 +440,7 @@ type WithValue interface { | ||||||
| // WithImage represents an activity with ActivityStreamsImageProperty | // WithImage represents an activity with ActivityStreamsImageProperty | ||||||
| type WithImage interface { | type WithImage interface { | ||||||
| 	GetActivityStreamsImage() vocab.ActivityStreamsImageProperty | 	GetActivityStreamsImage() vocab.ActivityStreamsImageProperty | ||||||
|  | 	SetActivityStreamsImage(vocab.ActivityStreamsImageProperty) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithSummary represents an activity with ActivityStreamsSummaryProperty | // WithSummary represents an activity with ActivityStreamsSummaryProperty | ||||||
|  |  | ||||||
|  | @ -177,38 +177,6 @@ func (suite *InboxPostTestSuite) newUndo( | ||||||
| 	return undo | 	return undo | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *InboxPostTestSuite) newUpdatePerson(person vocab.ActivityStreamsPerson, cc string, updateIRI string) vocab.ActivityStreamsUpdate { |  | ||||||
| 	// create an update |  | ||||||
| 	update := streams.NewActivityStreamsUpdate() |  | ||||||
| 
 |  | ||||||
| 	// set the appropriate actor on it |  | ||||||
| 	updateActor := streams.NewActivityStreamsActorProperty() |  | ||||||
| 	updateActor.AppendIRI(person.GetJSONLDId().Get()) |  | ||||||
| 	update.SetActivityStreamsActor(updateActor) |  | ||||||
| 
 |  | ||||||
| 	// Set the person as the 'object' property. |  | ||||||
| 	updateObject := streams.NewActivityStreamsObjectProperty() |  | ||||||
| 	updateObject.AppendActivityStreamsPerson(person) |  | ||||||
| 	update.SetActivityStreamsObject(updateObject) |  | ||||||
| 
 |  | ||||||
| 	// Set the To of the update as public |  | ||||||
| 	updateTo := streams.NewActivityStreamsToProperty() |  | ||||||
| 	updateTo.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) |  | ||||||
| 	update.SetActivityStreamsTo(updateTo) |  | ||||||
| 
 |  | ||||||
| 	// set the cc of the update to the receivingAccount |  | ||||||
| 	updateCC := streams.NewActivityStreamsCcProperty() |  | ||||||
| 	updateCC.AppendIRI(testrig.URLMustParse(cc)) |  | ||||||
| 	update.SetActivityStreamsCc(updateCC) |  | ||||||
| 
 |  | ||||||
| 	// set some random-ass ID for the activity |  | ||||||
| 	updateID := streams.NewJSONLDIdProperty() |  | ||||||
| 	updateID.SetIRI(testrig.URLMustParse(updateIRI)) |  | ||||||
| 	update.SetJSONLDId(updateID) |  | ||||||
| 
 |  | ||||||
| 	return update |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, deleteIRI string) vocab.ActivityStreamsDelete { | func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, deleteIRI string) vocab.ActivityStreamsDelete { | ||||||
| 	// create a delete | 	// create a delete | ||||||
| 	delete := streams.NewActivityStreamsDelete() | 	delete := streams.NewActivityStreamsDelete() | ||||||
|  | @ -225,7 +193,7 @@ func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, de | ||||||
| 
 | 
 | ||||||
| 	// Set the To of the delete as public | 	// Set the To of the delete as public | ||||||
| 	deleteTo := streams.NewActivityStreamsToProperty() | 	deleteTo := streams.NewActivityStreamsToProperty() | ||||||
| 	deleteTo.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI)) | 	deleteTo.AppendIRI(ap.PublicURI()) | ||||||
| 	delete.SetActivityStreamsTo(deleteTo) | 	delete.SetActivityStreamsTo(deleteTo) | ||||||
| 
 | 
 | ||||||
| 	// set some random-ass ID for the activity | 	// set some random-ass ID for the activity | ||||||
|  | @ -329,7 +297,6 @@ func (suite *InboxPostTestSuite) TestPostUpdate() { | ||||||
| 	var ( | 	var ( | ||||||
| 		requestingAccount  = new(gtsmodel.Account) | 		requestingAccount  = new(gtsmodel.Account) | ||||||
| 		targetAccount      = suite.testAccounts["local_account_1"] | 		targetAccount      = suite.testAccounts["local_account_1"] | ||||||
| 		activityID         = "http://fossbros-anonymous.io/72cc96a3-f742-4daf-b9f5-3407667260c5" |  | ||||||
| 		updatedDisplayName = "updated display name!" | 		updatedDisplayName = "updated display name!" | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
|  | @ -348,11 +315,19 @@ func (suite *InboxPostTestSuite) TestPostUpdate() { | ||||||
| 	requestingAccount.Emojis = []*gtsmodel.Emoji{testEmoji} | 	requestingAccount.Emojis = []*gtsmodel.Emoji{testEmoji} | ||||||
| 
 | 
 | ||||||
| 	// Create an update from the account. | 	// Create an update from the account. | ||||||
| 	asAccount, err := suite.tc.AccountToAS(context.Background(), requestingAccount) | 	accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 	update := suite.newUpdatePerson(asAccount, targetAccount.URI, activityID) | 	update, err := suite.tc.WrapAccountableInUpdate(accountable) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Set the ID to something from fossbros anonymous. | ||||||
|  | 	idProp := streams.NewJSONLDIdProperty() | ||||||
|  | 	idProp.SetIRI(testrig.URLMustParse("https://fossbros-anonymous.io/updates/waaaaaaaaaaaaaaaaa")) | ||||||
|  | 	update.SetJSONLDId(idProp) | ||||||
| 
 | 
 | ||||||
| 	// Update. | 	// Update. | ||||||
| 	suite.inboxPost( | 	suite.inboxPost( | ||||||
|  | @ -540,17 +515,20 @@ func (suite *InboxPostTestSuite) TestPostFromBlockedAccount() { | ||||||
| 	var ( | 	var ( | ||||||
| 		requestingAccount = suite.testAccounts["remote_account_1"] | 		requestingAccount = suite.testAccounts["remote_account_1"] | ||||||
| 		targetAccount     = suite.testAccounts["local_account_2"] | 		targetAccount     = suite.testAccounts["local_account_2"] | ||||||
| 		activityID        = requestingAccount.URI + "/some-new-activity/01FG9C441MCTW3R2W117V2PQK3" |  | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	person, err := suite.tc.AccountToAS(context.Background(), requestingAccount) | 	// Create an update from the account. | ||||||
|  | 	accountable, err := suite.tc.AccountToAS(context.Background(), requestingAccount) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 	update, err := suite.tc.WrapAccountableInUpdate(accountable) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Post an update from foss satan to turtle, who blocks him. | 	// Post an update from foss satan | ||||||
| 	update := suite.newUpdatePerson(person, targetAccount.URI, activityID) | 	// to turtle, who blocks him. | ||||||
| 
 |  | ||||||
| 	suite.inboxPost( | 	suite.inboxPost( | ||||||
| 		update, | 		update, | ||||||
| 		requestingAccount, | 		requestingAccount, | ||||||
|  |  | ||||||
|  | @ -75,12 +75,12 @@ func (suite *FederatorStandardTestSuite) SetupTest() { | ||||||
| 
 | 
 | ||||||
| 	// Ensure it's possible to deref | 	// Ensure it's possible to deref | ||||||
| 	// main key of foss satan. | 	// main key of foss satan. | ||||||
| 	fossSatanPerson, err := suite.typeconverter.AccountToAS(context.Background(), suite.testAccounts["remote_account_1"]) | 	fossSatanAS, err := suite.typeconverter.AccountToAS(context.Background(), suite.testAccounts["remote_account_1"]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	suite.httpClient = testrig.NewMockHTTPClient(nil, "../../testrig/media", fossSatanPerson) | 	suite.httpClient = testrig.NewMockHTTPClient(nil, "../../testrig/media", fossSatanAS) | ||||||
| 	suite.httpClient.TestRemotePeople = testrig.NewTestFediPeople() | 	suite.httpClient.TestRemotePeople = testrig.NewTestFediPeople() | ||||||
| 	suite.httpClient.TestRemoteStatuses = testrig.NewTestFediStatuses() | 	suite.httpClient.TestRemoteStatuses = testrig.NewTestFediStatuses() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,6 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" |  | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
|  | @ -72,7 +71,7 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Auth passed, generate the proper AP representation. | 	// Auth passed, generate the proper AP representation. | ||||||
| 	person, err := p.converter.AccountToAS(ctx, receiver) | 	accountable, err := p.converter.AccountToAS(ctx, receiver) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		err := gtserror.Newf("error converting account: %w", err) | 		err := gtserror.Newf("error converting account: %w", err) | ||||||
| 		return nil, gtserror.NewErrorInternalError(err) | 		return nil, gtserror.NewErrorInternalError(err) | ||||||
|  | @ -91,7 +90,7 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque | ||||||
| 		// Instead, we end up in an 'I'll show you mine if you show me | 		// Instead, we end up in an 'I'll show you mine if you show me | ||||||
| 		// yours' situation, where we sort of agree to reveal each | 		// yours' situation, where we sort of agree to reveal each | ||||||
| 		// other's profiles at the same time. | 		// other's profiles at the same time. | ||||||
| 		return data(person) | 		return data(accountable) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Get requester from auth. | 	// Get requester from auth. | ||||||
|  | @ -107,13 +106,13 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque | ||||||
| 		return nil, gtserror.NewErrorForbidden(errors.New(text)) | 		return nil, gtserror.NewErrorForbidden(errors.New(text)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return data(person) | 	return data(accountable) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func data(requestedPerson vocab.ActivityStreamsPerson) (interface{}, gtserror.WithCode) { | func data(accountable ap.Accountable) (interface{}, gtserror.WithCode) { | ||||||
| 	data, err := ap.Serialize(requestedPerson) | 	data, err := ap.Serialize(accountable) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		err := gtserror.Newf("error serializing person: %w", err) | 		err := gtserror.Newf("error serializing accountable: %w", err) | ||||||
| 		return nil, gtserror.NewErrorInternalError(err) | 		return nil, gtserror.NewErrorInternalError(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/activity/pub" |  | ||||||
| 	"github.com/superseriousbusiness/activity/streams" | 	"github.com/superseriousbusiness/activity/streams" | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
|  | @ -93,11 +92,6 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	publicIRI, err := parseURI(pub.PublicActivityPubIRI) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Create a new delete. | 	// Create a new delete. | ||||||
| 	// todo: tc.AccountToASDelete | 	// todo: tc.AccountToASDelete | ||||||
| 	delete := streams.NewActivityStreamsDelete() | 	delete := streams.NewActivityStreamsDelete() | ||||||
|  | @ -121,7 +115,7 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account) | ||||||
| 
 | 
 | ||||||
| 	// Address the delete CC public. | 	// Address the delete CC public. | ||||||
| 	deleteCC := streams.NewActivityStreamsCcProperty() | 	deleteCC := streams.NewActivityStreamsCcProperty() | ||||||
| 	deleteCC.AppendIRI(publicIRI) | 	deleteCC.AppendIRI(ap.PublicURI()) | ||||||
| 	delete.SetActivityStreamsCc(deleteCC) | 	delete.SetActivityStreamsCc(deleteCC) | ||||||
| 
 | 
 | ||||||
| 	// Send the Delete via the Actor's outbox. | 	// Send the Delete via the Actor's outbox. | ||||||
|  | @ -877,14 +871,14 @@ func (f *federate) UpdateAccount(ctx context.Context, account *gtsmodel.Account) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Convert account to ActivityStreams Person. | 	// Convert account to Accountable. | ||||||
| 	person, err := f.converter.AccountToAS(ctx, account) | 	accountable, err := f.converter.AccountToAS(ctx, account) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return gtserror.Newf("error converting account to Person: %w", err) | 		return gtserror.Newf("error converting account to Person: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Use ActivityStreams Person as Object of Update. | 	// Use Accountable as Object of Update. | ||||||
| 	update, err := f.converter.WrapPersonInUpdate(person, account) | 	update, err := f.converter.WrapAccountableInUpdate(accountable) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return gtserror.Newf("error wrapping Person in Update: %w", err) | 		return gtserror.Newf("error wrapping Person in Update: %w", err) | ||||||
| 	} | 	} | ||||||
|  | @ -1089,11 +1083,6 @@ func (f *federate) MoveAccount(ctx context.Context, account *gtsmodel.Account) e | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	publicIRI, err := parseURI(pub.PublicActivityPubIRI) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Create a new move. | 	// Create a new move. | ||||||
| 	move := streams.NewActivityStreamsMove() | 	move := streams.NewActivityStreamsMove() | ||||||
| 
 | 
 | ||||||
|  | @ -1115,7 +1104,7 @@ func (f *federate) MoveAccount(ctx context.Context, account *gtsmodel.Account) e | ||||||
| 	ap.AppendTo(move, followersIRI) | 	ap.AppendTo(move, followersIRI) | ||||||
| 
 | 
 | ||||||
| 	// Address the move CC public. | 	// Address the move CC public. | ||||||
| 	ap.AppendCc(move, publicIRI) | 	ap.AppendCc(move, ap.PublicURI()) | ||||||
| 
 | 
 | ||||||
| 	// Send the Move via the Actor's outbox. | 	// Send the Move via the Actor's outbox. | ||||||
| 	if _, err := f.FederatingActor().Send( | 	if _, err := f.FederatingActor().Send( | ||||||
|  |  | ||||||
|  | @ -36,12 +36,24 @@ import ( | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/log" | 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/uris" | 	"github.com/superseriousbusiness/gotosocial/internal/uris" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/util/xslices" | 	"github.com/superseriousbusiness/gotosocial/internal/util/xslices" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // AccountToAS converts a gts model account into an activity streams person, suitable for federation | // AccountToAS converts a gts model account | ||||||
| func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab.ActivityStreamsPerson, error) { | // into an activity streams person or service. | ||||||
| 	person := streams.NewActivityStreamsPerson() | func (c *Converter) AccountToAS( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	a *gtsmodel.Account, | ||||||
|  | ) (ap.Accountable, error) { | ||||||
|  | 	// accountable is a service if this | ||||||
|  | 	// is a bot account, otherwise a person. | ||||||
|  | 	var accountable ap.Accountable | ||||||
|  | 	if util.PtrOrZero(a.Bot) { | ||||||
|  | 		accountable = streams.NewActivityStreamsService() | ||||||
|  | 	} else { | ||||||
|  | 		accountable = streams.NewActivityStreamsPerson() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// id should be the activitypub URI of this user | 	// id should be the activitypub URI of this user | ||||||
| 	// something like https://example.org/users/example_user | 	// something like https://example.org/users/example_user | ||||||
|  | @ -51,13 +63,13 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	idProp := streams.NewJSONLDIdProperty() | 	idProp := streams.NewJSONLDIdProperty() | ||||||
| 	idProp.SetIRI(profileIDURI) | 	idProp.SetIRI(profileIDURI) | ||||||
| 	person.SetJSONLDId(idProp) | 	accountable.SetJSONLDId(idProp) | ||||||
| 
 | 
 | ||||||
| 	// published | 	// published | ||||||
| 	// The moment when the account was created. | 	// The moment when the account was created. | ||||||
| 	publishedProp := streams.NewActivityStreamsPublishedProperty() | 	publishedProp := streams.NewActivityStreamsPublishedProperty() | ||||||
| 	publishedProp.Set(a.CreatedAt) | 	publishedProp.Set(a.CreatedAt) | ||||||
| 	person.SetActivityStreamsPublished(publishedProp) | 	accountable.SetActivityStreamsPublished(publishedProp) | ||||||
| 
 | 
 | ||||||
| 	// following | 	// following | ||||||
| 	// The URI for retrieving a list of accounts this user is following | 	// The URI for retrieving a list of accounts this user is following | ||||||
|  | @ -67,7 +79,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	followingProp := streams.NewActivityStreamsFollowingProperty() | 	followingProp := streams.NewActivityStreamsFollowingProperty() | ||||||
| 	followingProp.SetIRI(followingURI) | 	followingProp.SetIRI(followingURI) | ||||||
| 	person.SetActivityStreamsFollowing(followingProp) | 	accountable.SetActivityStreamsFollowing(followingProp) | ||||||
| 
 | 
 | ||||||
| 	// followers | 	// followers | ||||||
| 	// The URI for retrieving a list of this user's followers | 	// The URI for retrieving a list of this user's followers | ||||||
|  | @ -77,7 +89,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	followersProp := streams.NewActivityStreamsFollowersProperty() | 	followersProp := streams.NewActivityStreamsFollowersProperty() | ||||||
| 	followersProp.SetIRI(followersURI) | 	followersProp.SetIRI(followersURI) | ||||||
| 	person.SetActivityStreamsFollowers(followersProp) | 	accountable.SetActivityStreamsFollowers(followersProp) | ||||||
| 
 | 
 | ||||||
| 	// inbox | 	// inbox | ||||||
| 	// the activitypub inbox of this user for accepting messages | 	// the activitypub inbox of this user for accepting messages | ||||||
|  | @ -87,7 +99,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	inboxProp := streams.NewActivityStreamsInboxProperty() | 	inboxProp := streams.NewActivityStreamsInboxProperty() | ||||||
| 	inboxProp.SetIRI(inboxURI) | 	inboxProp.SetIRI(inboxURI) | ||||||
| 	person.SetActivityStreamsInbox(inboxProp) | 	accountable.SetActivityStreamsInbox(inboxProp) | ||||||
| 
 | 
 | ||||||
| 	// shared inbox -- only add this if we know for sure it has one | 	// shared inbox -- only add this if we know for sure it has one | ||||||
| 	if a.SharedInboxURI != nil && *a.SharedInboxURI != "" { | 	if a.SharedInboxURI != nil && *a.SharedInboxURI != "" { | ||||||
|  | @ -101,7 +113,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 		sharedInboxProp.SetIRI(sharedInboxURI) | 		sharedInboxProp.SetIRI(sharedInboxURI) | ||||||
| 		endpoints.SetActivityStreamsSharedInbox(sharedInboxProp) | 		endpoints.SetActivityStreamsSharedInbox(sharedInboxProp) | ||||||
| 		endpointsProp.AppendActivityStreamsEndpoints(endpoints) | 		endpointsProp.AppendActivityStreamsEndpoints(endpoints) | ||||||
| 		person.SetActivityStreamsEndpoints(endpointsProp) | 		accountable.SetActivityStreamsEndpoints(endpointsProp) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// outbox | 	// outbox | ||||||
|  | @ -112,7 +124,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	outboxProp := streams.NewActivityStreamsOutboxProperty() | 	outboxProp := streams.NewActivityStreamsOutboxProperty() | ||||||
| 	outboxProp.SetIRI(outboxURI) | 	outboxProp.SetIRI(outboxURI) | ||||||
| 	person.SetActivityStreamsOutbox(outboxProp) | 	accountable.SetActivityStreamsOutbox(outboxProp) | ||||||
| 
 | 
 | ||||||
| 	// featured posts | 	// featured posts | ||||||
| 	// Pinned posts. | 	// Pinned posts. | ||||||
|  | @ -122,7 +134,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	featuredProp := streams.NewTootFeaturedProperty() | 	featuredProp := streams.NewTootFeaturedProperty() | ||||||
| 	featuredProp.SetIRI(featuredURI) | 	featuredProp.SetIRI(featuredURI) | ||||||
| 	person.SetTootFeatured(featuredProp) | 	accountable.SetTootFeatured(featuredProp) | ||||||
| 
 | 
 | ||||||
| 	// featuredTags | 	// featuredTags | ||||||
| 	// NOT IMPLEMENTED | 	// NOT IMPLEMENTED | ||||||
|  | @ -131,7 +143,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. | 	// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. | ||||||
| 	preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() | 	preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() | ||||||
| 	preferredUsernameProp.SetXMLSchemaString(a.Username) | 	preferredUsernameProp.SetXMLSchemaString(a.Username) | ||||||
| 	person.SetActivityStreamsPreferredUsername(preferredUsernameProp) | 	accountable.SetActivityStreamsPreferredUsername(preferredUsernameProp) | ||||||
| 
 | 
 | ||||||
| 	// name | 	// name | ||||||
| 	// Used as profile display name. | 	// Used as profile display name. | ||||||
|  | @ -141,14 +153,14 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} else { | 	} else { | ||||||
| 		nameProp.AppendXMLSchemaString(a.Username) | 		nameProp.AppendXMLSchemaString(a.Username) | ||||||
| 	} | 	} | ||||||
| 	person.SetActivityStreamsName(nameProp) | 	accountable.SetActivityStreamsName(nameProp) | ||||||
| 
 | 
 | ||||||
| 	// summary | 	// summary | ||||||
| 	// Used as profile bio. | 	// Used as profile bio. | ||||||
| 	if a.Note != "" { | 	if a.Note != "" { | ||||||
| 		summaryProp := streams.NewActivityStreamsSummaryProperty() | 		summaryProp := streams.NewActivityStreamsSummaryProperty() | ||||||
| 		summaryProp.AppendXMLSchemaString(a.Note) | 		summaryProp.AppendXMLSchemaString(a.Note) | ||||||
| 		person.SetActivityStreamsSummary(summaryProp) | 		accountable.SetActivityStreamsSummary(summaryProp) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// url | 	// url | ||||||
|  | @ -159,19 +171,19 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	} | 	} | ||||||
| 	urlProp := streams.NewActivityStreamsUrlProperty() | 	urlProp := streams.NewActivityStreamsUrlProperty() | ||||||
| 	urlProp.AppendIRI(profileURL) | 	urlProp.AppendIRI(profileURL) | ||||||
| 	person.SetActivityStreamsUrl(urlProp) | 	accountable.SetActivityStreamsUrl(urlProp) | ||||||
| 
 | 
 | ||||||
| 	// manuallyApprovesFollowers | 	// manuallyApprovesFollowers | ||||||
| 	// Will be shown as a locked account. | 	// Will be shown as a locked account. | ||||||
| 	manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() | 	manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() | ||||||
| 	manuallyApprovesFollowersProp.Set(*a.Locked) | 	manuallyApprovesFollowersProp.Set(*a.Locked) | ||||||
| 	person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) | 	accountable.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) | ||||||
| 
 | 
 | ||||||
| 	// discoverable | 	// discoverable | ||||||
| 	// Will be shown in the profile directory. | 	// Will be shown in the profile directory. | ||||||
| 	discoverableProp := streams.NewTootDiscoverableProperty() | 	discoverableProp := streams.NewTootDiscoverableProperty() | ||||||
| 	discoverableProp.Set(*a.Discoverable) | 	discoverableProp.Set(*a.Discoverable) | ||||||
| 	person.SetTootDiscoverable(discoverableProp) | 	accountable.SetTootDiscoverable(discoverableProp) | ||||||
| 
 | 
 | ||||||
| 	// devices | 	// devices | ||||||
| 	// NOT IMPLEMENTED, probably won't implement | 	// NOT IMPLEMENTED, probably won't implement | ||||||
|  | @ -189,7 +201,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 			alsoKnownAsURIs[i] = uri | 			alsoKnownAsURIs[i] = uri | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ap.SetAlsoKnownAs(person, alsoKnownAsURIs) | 		ap.SetAlsoKnownAs(accountable, alsoKnownAsURIs) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// movedTo | 	// movedTo | ||||||
|  | @ -200,7 +212,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ap.SetMovedTo(person, movedTo) | 		ap.SetMovedTo(accountable, movedTo) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// publicKey | 	// publicKey | ||||||
|  | @ -241,7 +253,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) | 	publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) | ||||||
| 
 | 
 | ||||||
| 	// set the public key property on the Person | 	// set the public key property on the Person | ||||||
| 	person.SetW3IDSecurityV1PublicKey(publicKeyProp) | 	accountable.SetW3IDSecurityV1PublicKey(publicKeyProp) | ||||||
| 
 | 
 | ||||||
| 	// tags | 	// tags | ||||||
| 	tagProp := streams.NewActivityStreamsTagProperty() | 	tagProp := streams.NewActivityStreamsTagProperty() | ||||||
|  | @ -269,7 +281,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 	// tag -- hashtags | 	// tag -- hashtags | ||||||
| 	// TODO | 	// TODO | ||||||
| 
 | 
 | ||||||
| 	person.SetActivityStreamsTag(tagProp) | 	accountable.SetActivityStreamsTag(tagProp) | ||||||
| 
 | 
 | ||||||
| 	// attachment | 	// attachment | ||||||
| 	// Used for profile fields. | 	// Used for profile fields. | ||||||
|  | @ -290,7 +302,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 			attachmentProp.AppendSchemaPropertyValue(propertyValue) | 			attachmentProp.AppendSchemaPropertyValue(propertyValue) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		person.SetActivityStreamsAttachment(attachmentProp) | 		accountable.SetActivityStreamsAttachment(attachmentProp) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// endpoints | 	// endpoints | ||||||
|  | @ -326,7 +338,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 			iconImage.SetActivityStreamsUrl(avatarURLProperty) | 			iconImage.SetActivityStreamsUrl(avatarURLProperty) | ||||||
| 
 | 
 | ||||||
| 			iconProperty.AppendActivityStreamsImage(iconImage) | 			iconProperty.AppendActivityStreamsImage(iconImage) | ||||||
| 			person.SetActivityStreamsIcon(iconProperty) | 			accountable.SetActivityStreamsIcon(iconProperty) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -360,20 +372,32 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab | ||||||
| 			headerImage.SetActivityStreamsUrl(headerURLProperty) | 			headerImage.SetActivityStreamsUrl(headerURLProperty) | ||||||
| 
 | 
 | ||||||
| 			headerProperty.AppendActivityStreamsImage(headerImage) | 			headerProperty.AppendActivityStreamsImage(headerImage) | ||||||
| 			person.SetActivityStreamsImage(headerProperty) | 			accountable.SetActivityStreamsImage(headerProperty) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return person, nil | 	return accountable, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // AccountToASMinimal converts a gts model account into an activity streams person, suitable for federation. | // AccountToASMinimal converts a gts model account | ||||||
|  | // into an activity streams person or service. | ||||||
| // | // | ||||||
| // The returned account will just have the Type, Username, PublicKey, and ID properties set. This is | // The returned account will just have the Type, Username, | ||||||
| // suitable for serving to requesters to whom we want to give as little information as possible because | // PublicKey, and ID properties set. This is suitable for | ||||||
| // we don't trust them (yet). | // serving to requesters to whom we want to give as little | ||||||
| func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account) (vocab.ActivityStreamsPerson, error) { | // information as possible because we don't trust them (yet). | ||||||
| 	person := streams.NewActivityStreamsPerson() | func (c *Converter) AccountToASMinimal( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	a *gtsmodel.Account, | ||||||
|  | ) (ap.Accountable, error) { | ||||||
|  | 	// accountable is a service if this | ||||||
|  | 	// is a bot account, otherwise a person. | ||||||
|  | 	var accountable ap.Accountable | ||||||
|  | 	if util.PtrOrZero(a.Bot) { | ||||||
|  | 		accountable = streams.NewActivityStreamsService() | ||||||
|  | 	} else { | ||||||
|  | 		accountable = streams.NewActivityStreamsPerson() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// id should be the activitypub URI of this user | 	// id should be the activitypub URI of this user | ||||||
| 	// something like https://example.org/users/example_user | 	// something like https://example.org/users/example_user | ||||||
|  | @ -383,13 +407,13 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account) | ||||||
| 	} | 	} | ||||||
| 	idProp := streams.NewJSONLDIdProperty() | 	idProp := streams.NewJSONLDIdProperty() | ||||||
| 	idProp.SetIRI(profileIDURI) | 	idProp.SetIRI(profileIDURI) | ||||||
| 	person.SetJSONLDId(idProp) | 	accountable.SetJSONLDId(idProp) | ||||||
| 
 | 
 | ||||||
| 	// preferredUsername | 	// preferredUsername | ||||||
| 	// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. | 	// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. | ||||||
| 	preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() | 	preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() | ||||||
| 	preferredUsernameProp.SetXMLSchemaString(a.Username) | 	preferredUsernameProp.SetXMLSchemaString(a.Username) | ||||||
| 	person.SetActivityStreamsPreferredUsername(preferredUsernameProp) | 	accountable.SetActivityStreamsPreferredUsername(preferredUsernameProp) | ||||||
| 
 | 
 | ||||||
| 	// publicKey | 	// publicKey | ||||||
| 	// Required for signatures. | 	// Required for signatures. | ||||||
|  | @ -429,9 +453,9 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account) | ||||||
| 	publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) | 	publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) | ||||||
| 
 | 
 | ||||||
| 	// set the public key property on the Person | 	// set the public key property on the Person | ||||||
| 	person.SetW3IDSecurityV1PublicKey(publicKeyProp) | 	accountable.SetW3IDSecurityV1PublicKey(publicKeyProp) | ||||||
| 
 | 
 | ||||||
| 	return person, nil | 	return accountable, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // StatusToAS converts a gts model status into an ActivityStreams Statusable implementation, suitable for federation | // StatusToAS converts a gts model status into an ActivityStreams Statusable implementation, suitable for federation | ||||||
|  |  | ||||||
|  | @ -27,6 +27,7 @@ import ( | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/testrig" | 	"github.com/superseriousbusiness/gotosocial/testrig" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -38,10 +39,10 @@ func (suite *InternalToASTestSuite) TestAccountToAS() { | ||||||
| 	testAccount := >smodel.Account{} | 	testAccount := >smodel.Account{} | ||||||
| 	*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test | 	*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | @ -94,14 +95,80 @@ func (suite *InternalToASTestSuite) TestAccountToAS() { | ||||||
| }`, string(bytes)) | }`, string(bytes)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (suite *InternalToASTestSuite) TestAccountToASBot() { | ||||||
|  | 	testAccount := >smodel.Account{} | ||||||
|  | 	*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test | ||||||
|  | 
 | ||||||
|  | 	// Update zork to be a bot. | ||||||
|  | 	testAccount.Bot = util.Ptr(true) | ||||||
|  | 	if err := suite.state.DB.UpdateAccount(context.Background(), testAccount); err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 
 | ||||||
|  | 	ser, err := ap.Serialize(accountable) | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 
 | ||||||
|  | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 
 | ||||||
|  | 	suite.Equal(`{ | ||||||
|  |   "@context": [ | ||||||
|  |     "https://w3id.org/security/v1", | ||||||
|  |     "https://www.w3.org/ns/activitystreams", | ||||||
|  |     { | ||||||
|  |       "discoverable": "toot:discoverable", | ||||||
|  |       "featured": { | ||||||
|  |         "@id": "toot:featured", | ||||||
|  |         "@type": "@id" | ||||||
|  |       }, | ||||||
|  |       "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", | ||||||
|  |       "toot": "http://joinmastodon.org/ns#" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "discoverable": true, | ||||||
|  |   "featured": "http://localhost:8080/users/the_mighty_zork/collections/featured", | ||||||
|  |   "followers": "http://localhost:8080/users/the_mighty_zork/followers", | ||||||
|  |   "following": "http://localhost:8080/users/the_mighty_zork/following", | ||||||
|  |   "icon": { | ||||||
|  |     "mediaType": "image/jpeg", | ||||||
|  |     "type": "Image", | ||||||
|  |     "url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg" | ||||||
|  |   }, | ||||||
|  |   "id": "http://localhost:8080/users/the_mighty_zork", | ||||||
|  |   "image": { | ||||||
|  |     "mediaType": "image/jpeg", | ||||||
|  |     "type": "Image", | ||||||
|  |     "url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg" | ||||||
|  |   }, | ||||||
|  |   "inbox": "http://localhost:8080/users/the_mighty_zork/inbox", | ||||||
|  |   "manuallyApprovesFollowers": false, | ||||||
|  |   "name": "original zork (he/they)", | ||||||
|  |   "outbox": "http://localhost:8080/users/the_mighty_zork/outbox", | ||||||
|  |   "preferredUsername": "the_mighty_zork", | ||||||
|  |   "publicKey": { | ||||||
|  |     "id": "http://localhost:8080/users/the_mighty_zork/main-key", | ||||||
|  |     "owner": "http://localhost:8080/users/the_mighty_zork", | ||||||
|  |     "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXTcOAvM1Jiw5Ffpk0qn\nr0cwbNvFe/5zQ+Tp7tumK/ZnT37o7X0FUEXrxNi+dkhmeJ0gsaiN+JQGNUewvpSk\nPIAXKvi908aSfCGjs7bGlJCJCuDuL5d6m7hZnP9rt9fJc70GElPpG0jc9fXwlz7T\nlsPb2ecatmG05Y4jPwdC+oN4MNCv9yQzEvCVMzl76EJaM602kIHC1CISn0rDFmYd\n9rSN7XPlNJw1F6PbpJ/BWQ+pXHKw3OEwNTETAUNYiVGnZU+B7a7bZC9f6/aPbJuV\nt8Qmg+UnDvW1Y8gmfHnxaWG2f5TDBvCHmcYtucIZPLQD4trAozC4ryqlmCWQNKbt\n0wIDAQAB\n-----END PUBLIC KEY-----\n" | ||||||
|  |   }, | ||||||
|  |   "published": "2022-05-20T11:09:18Z", | ||||||
|  |   "summary": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e", | ||||||
|  |   "tag": [], | ||||||
|  |   "type": "Service", | ||||||
|  |   "url": "http://localhost:8080/@the_mighty_zork" | ||||||
|  | }`, string(bytes)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (suite *InternalToASTestSuite) TestAccountToASWithFields() { | func (suite *InternalToASTestSuite) TestAccountToASWithFields() { | ||||||
| 	testAccount := >smodel.Account{} | 	testAccount := >smodel.Account{} | ||||||
| 	*testAccount = *suite.testAccounts["local_account_2"] | 	*testAccount = *suite.testAccounts["local_account_2"] | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | @ -176,10 +243,10 @@ func (suite *InternalToASTestSuite) TestAccountToASAliasedAndMoved() { | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | @ -246,10 +313,10 @@ func (suite *InternalToASTestSuite) TestAccountToASWithOneField() { | ||||||
| 	*testAccount = *suite.testAccounts["local_account_2"] | 	*testAccount = *suite.testAccounts["local_account_2"] | ||||||
| 	testAccount.Fields = testAccount.Fields[0:1] // Take only one field. | 	testAccount.Fields = testAccount.Fields[0:1] // Take only one field. | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | @ -308,10 +375,10 @@ func (suite *InternalToASTestSuite) TestAccountToASWithEmoji() { | ||||||
| 	*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test | 	*testAccount = *suite.testAccounts["local_account_1"] // take zork for this test | ||||||
| 	testAccount.Emojis = []*gtsmodel.Emoji{suite.testEmojis["rainbow"]} | 	testAccount.Emojis = []*gtsmodel.Emoji{suite.testEmojis["rainbow"]} | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  | @ -381,10 +448,10 @@ func (suite *InternalToASTestSuite) TestAccountToASWithSharedInbox() { | ||||||
| 	sharedInbox := "http://localhost:8080/sharedInbox" | 	sharedInbox := "http://localhost:8080/sharedInbox" | ||||||
| 	testAccount.SharedInboxURI = &sharedInbox | 	testAccount.SharedInboxURI = &sharedInbox | ||||||
| 
 | 
 | ||||||
| 	asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	ser, err := ap.Serialize(asPerson) | 	ser, err := ap.Serialize(accountable) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
| 	bytes, err := json.MarshalIndent(ser, "", "  ") | 	bytes, err := json.MarshalIndent(ser, "", "  ") | ||||||
|  |  | ||||||
|  | @ -18,68 +18,45 @@ | ||||||
| package typeutils | package typeutils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"net/url" |  | ||||||
| 
 |  | ||||||
| 	"github.com/superseriousbusiness/activity/pub" |  | ||||||
| 	"github.com/superseriousbusiness/activity/streams" | 	"github.com/superseriousbusiness/activity/streams" | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" |  | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" |  | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/id" | 	"github.com/superseriousbusiness/gotosocial/internal/id" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/uris" | 	"github.com/superseriousbusiness/gotosocial/internal/uris" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // WrapPersonInUpdate ... | // WrapAccountableInUpdate wraps the given accountable | ||||||
| func (c *Converter) WrapPersonInUpdate(person vocab.ActivityStreamsPerson, originAccount *gtsmodel.Account) (vocab.ActivityStreamsUpdate, error) { | // in an Update activity with the accountable as the object. | ||||||
|  | // | ||||||
|  | // The Update will be addressed to Public and bcc followers. | ||||||
|  | func (c *Converter) WrapAccountableInUpdate(accountable ap.Accountable) (vocab.ActivityStreamsUpdate, error) { | ||||||
| 	update := streams.NewActivityStreamsUpdate() | 	update := streams.NewActivityStreamsUpdate() | ||||||
| 
 | 
 | ||||||
| 	// set the actor | 	// Set actor IRI to this accountable's IRI. | ||||||
| 	actorURI, err := url.Parse(originAccount.URI) | 	ap.AppendActorIRIs(update, ap.GetJSONLDId(accountable)) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, gtserror.Newf("error parsing url %s: %w", originAccount.URI, err) |  | ||||||
| 	} |  | ||||||
| 	actorProp := streams.NewActivityStreamsActorProperty() |  | ||||||
| 	actorProp.AppendIRI(actorURI) |  | ||||||
| 	update.SetActivityStreamsActor(actorProp) |  | ||||||
| 
 | 
 | ||||||
| 	// set the ID | 	// Set the update ID | ||||||
| 	newID, err := id.NewRandomULID() | 	updateURI := uris.GenerateURIForUpdate(ap.ExtractPreferredUsername(accountable), id.NewULID()) | ||||||
| 	if err != nil { | 	ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(update), updateURI) | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	idString := uris.GenerateURIForUpdate(originAccount.Username, newID) | 	// Set the accountable as the object of the update. | ||||||
| 	idURI, err := url.Parse(idString) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, gtserror.Newf("error parsing url %s: %w", idString, err) |  | ||||||
| 	} |  | ||||||
| 	idProp := streams.NewJSONLDIdProperty() |  | ||||||
| 	idProp.SetIRI(idURI) |  | ||||||
| 	update.SetJSONLDId(idProp) |  | ||||||
| 
 |  | ||||||
| 	// set the person as the object here |  | ||||||
| 	objectProp := streams.NewActivityStreamsObjectProperty() | 	objectProp := streams.NewActivityStreamsObjectProperty() | ||||||
| 	objectProp.AppendActivityStreamsPerson(person) | 	switch t := accountable.(type) { | ||||||
|  | 	case vocab.ActivityStreamsPerson: | ||||||
|  | 		objectProp.AppendActivityStreamsPerson(t) | ||||||
|  | 	case vocab.ActivityStreamsService: | ||||||
|  | 		objectProp.AppendActivityStreamsService(t) | ||||||
|  | 	default: | ||||||
|  | 		log.Panicf(nil, "%T was neither person nor service", t) | ||||||
|  | 	} | ||||||
| 	update.SetActivityStreamsObject(objectProp) | 	update.SetActivityStreamsObject(objectProp) | ||||||
| 
 | 
 | ||||||
| 	// to should be public | 	// to should be public. | ||||||
| 	toURI, err := url.Parse(pub.PublicActivityPubIRI) | 	ap.AppendTo(update, ap.PublicURI()) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, gtserror.Newf("error parsing url %s: %w", pub.PublicActivityPubIRI, err) |  | ||||||
| 	} |  | ||||||
| 	toProp := streams.NewActivityStreamsToProperty() |  | ||||||
| 	toProp.AppendIRI(toURI) |  | ||||||
| 	update.SetActivityStreamsTo(toProp) |  | ||||||
| 
 | 
 | ||||||
| 	// bcc followers | 	// bcc should be followers. | ||||||
| 	followersURI, err := url.Parse(originAccount.FollowersURI) | 	ap.AppendBcc(update, ap.GetFollowers(accountable)) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, gtserror.Newf("error parsing url %s: %w", originAccount.FollowersURI, err) |  | ||||||
| 	} |  | ||||||
| 	bccProp := streams.NewActivityStreamsBccProperty() |  | ||||||
| 	bccProp.AppendIRI(followersURI) |  | ||||||
| 	update.SetActivityStreamsBcc(bccProp) |  | ||||||
| 
 | 
 | ||||||
| 	return update, nil | 	return update, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -139,6 +139,86 @@ func (suite *WrapTestSuite) TestWrapNoteInCreate() { | ||||||
| }`, string(bytes)) | }`, string(bytes)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (suite *WrapTestSuite) TestWrapAccountableInUpdate() { | ||||||
|  | 	testAccount := suite.testAccounts["local_account_1"] | ||||||
|  | 
 | ||||||
|  | 	accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	create, err := suite.typeconverter.WrapAccountableInUpdate(accountable) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	createI, err := ap.Serialize(create) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Get the ID as it's not determinate. | ||||||
|  | 	createID := ap.GetJSONLDId(create) | ||||||
|  | 
 | ||||||
|  | 	bytes, err := json.MarshalIndent(createI, "", "  ") | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	suite.Equal(`{ | ||||||
|  |   "@context": [ | ||||||
|  |     "https://w3id.org/security/v1", | ||||||
|  |     "https://www.w3.org/ns/activitystreams", | ||||||
|  |     { | ||||||
|  |       "discoverable": "toot:discoverable", | ||||||
|  |       "featured": { | ||||||
|  |         "@id": "toot:featured", | ||||||
|  |         "@type": "@id" | ||||||
|  |       }, | ||||||
|  |       "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", | ||||||
|  |       "toot": "http://joinmastodon.org/ns#" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "actor": "http://localhost:8080/users/the_mighty_zork", | ||||||
|  |   "bcc": "http://localhost:8080/users/the_mighty_zork/followers", | ||||||
|  |   "id": "`+createID.String()+`", | ||||||
|  |   "object": { | ||||||
|  |     "discoverable": true, | ||||||
|  |     "featured": "http://localhost:8080/users/the_mighty_zork/collections/featured", | ||||||
|  |     "followers": "http://localhost:8080/users/the_mighty_zork/followers", | ||||||
|  |     "following": "http://localhost:8080/users/the_mighty_zork/following", | ||||||
|  |     "icon": { | ||||||
|  |       "mediaType": "image/jpeg", | ||||||
|  |       "type": "Image", | ||||||
|  |       "url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg" | ||||||
|  |     }, | ||||||
|  |     "id": "http://localhost:8080/users/the_mighty_zork", | ||||||
|  |     "image": { | ||||||
|  |       "mediaType": "image/jpeg", | ||||||
|  |       "type": "Image", | ||||||
|  |       "url": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg" | ||||||
|  |     }, | ||||||
|  |     "inbox": "http://localhost:8080/users/the_mighty_zork/inbox", | ||||||
|  |     "manuallyApprovesFollowers": false, | ||||||
|  |     "name": "original zork (he/they)", | ||||||
|  |     "outbox": "http://localhost:8080/users/the_mighty_zork/outbox", | ||||||
|  |     "preferredUsername": "the_mighty_zork", | ||||||
|  |     "publicKey": { | ||||||
|  |       "id": "http://localhost:8080/users/the_mighty_zork/main-key", | ||||||
|  |       "owner": "http://localhost:8080/users/the_mighty_zork", | ||||||
|  |       "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXTcOAvM1Jiw5Ffpk0qn\nr0cwbNvFe/5zQ+Tp7tumK/ZnT37o7X0FUEXrxNi+dkhmeJ0gsaiN+JQGNUewvpSk\nPIAXKvi908aSfCGjs7bGlJCJCuDuL5d6m7hZnP9rt9fJc70GElPpG0jc9fXwlz7T\nlsPb2ecatmG05Y4jPwdC+oN4MNCv9yQzEvCVMzl76EJaM602kIHC1CISn0rDFmYd\n9rSN7XPlNJw1F6PbpJ/BWQ+pXHKw3OEwNTETAUNYiVGnZU+B7a7bZC9f6/aPbJuV\nt8Qmg+UnDvW1Y8gmfHnxaWG2f5TDBvCHmcYtucIZPLQD4trAozC4ryqlmCWQNKbt\n0wIDAQAB\n-----END PUBLIC KEY-----\n" | ||||||
|  |     }, | ||||||
|  |     "published": "2022-05-20T11:09:18Z", | ||||||
|  |     "summary": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e", | ||||||
|  |     "tag": [], | ||||||
|  |     "type": "Person", | ||||||
|  |     "url": "http://localhost:8080/@the_mighty_zork" | ||||||
|  |   }, | ||||||
|  |   "to": "https://www.w3.org/ns/activitystreams#Public", | ||||||
|  |   "type": "Update" | ||||||
|  | }`, string(bytes)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestWrapTestSuite(t *testing.T) { | func TestWrapTestSuite(t *testing.T) { | ||||||
| 	suite.Run(t, new(WrapTestSuite)) | 	suite.Run(t, new(WrapTestSuite)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2853,7 +2853,7 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit | ||||||
| 		"this is a public status, please forward it!", | 		"this is a public status, please forward it!", | ||||||
| 		"", | 		"", | ||||||
| 		URLMustParse("http://example.org/users/Some_User"), | 		URLMustParse("http://example.org/users/Some_User"), | ||||||
| 		[]*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, | 		[]*url.URL{ap.PublicURI()}, | ||||||
| 		nil, | 		nil, | ||||||
| 		false, | 		false, | ||||||
| 		[]vocab.ActivityStreamsMention{}, | 		[]vocab.ActivityStreamsMention{}, | ||||||
|  | @ -3207,7 +3207,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"this is a public status, please forward it!", | 			"this is a public status, please forward it!", | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("http://example.org/users/Some_User"), | 			URLMustParse("http://example.org/users/Some_User"), | ||||||
| 			[]*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, | 			[]*url.URL{ap.PublicURI()}, | ||||||
| 			nil, | 			nil, | ||||||
| 			false, | 			false, | ||||||
| 			[]vocab.ActivityStreamsMention{}, | 			[]vocab.ActivityStreamsMention{}, | ||||||
|  | @ -3228,7 +3228,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | ||||||
| 			[]*url.URL{ | 			[]*url.URL{ | ||||||
| 				URLMustParse(pub.PublicActivityPubIRI), | 				ap.PublicURI(), | ||||||
| 			}, | 			}, | ||||||
| 			[]*url.URL{}, | 			[]*url.URL{}, | ||||||
| 			false, | 			false, | ||||||
|  | @ -3244,7 +3244,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | ||||||
| 			[]*url.URL{ | 			[]*url.URL{ | ||||||
| 				URLMustParse(pub.PublicActivityPubIRI), | 				ap.PublicURI(), | ||||||
| 			}, | 			}, | ||||||
| 			[]*url.URL{}, | 			[]*url.URL{}, | ||||||
| 			false, | 			false, | ||||||
|  | @ -3265,7 +3265,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | 			URLMustParse("https://unknown-instance.com/users/brand_new_person"), | ||||||
| 			[]*url.URL{ | 			[]*url.URL{ | ||||||
| 				URLMustParse(pub.PublicActivityPubIRI), | 				ap.PublicURI(), | ||||||
| 			}, | 			}, | ||||||
| 			[]*url.URL{}, | 			[]*url.URL{}, | ||||||
| 			false, | 			false, | ||||||
|  | @ -3286,7 +3286,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("https://turnip.farm/users/turniplover6969"), | 			URLMustParse("https://turnip.farm/users/turniplover6969"), | ||||||
| 			[]*url.URL{ | 			[]*url.URL{ | ||||||
| 				URLMustParse(pub.PublicActivityPubIRI), | 				ap.PublicURI(), | ||||||
| 			}, | 			}, | ||||||
| 			[]*url.URL{}, | 			[]*url.URL{}, | ||||||
| 			false, | 			false, | ||||||
|  | @ -3309,7 +3309,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { | ||||||
| 			"", | 			"", | ||||||
| 			URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), | 			URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), | ||||||
| 			[]*url.URL{ | 			[]*url.URL{ | ||||||
| 				URLMustParse(pub.PublicActivityPubIRI), | 				ap.PublicURI(), | ||||||
| 			}, | 			}, | ||||||
| 			[]*url.URL{}, | 			[]*url.URL{}, | ||||||
| 			false, | 			false, | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ import ( | ||||||
| 	"github.com/superseriousbusiness/activity/pub" | 	"github.com/superseriousbusiness/activity/pub" | ||||||
| 	"github.com/superseriousbusiness/activity/streams" | 	"github.com/superseriousbusiness/activity/streams" | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
| 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/federation" | 	"github.com/superseriousbusiness/gotosocial/internal/federation" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
|  | @ -81,7 +82,7 @@ type MockHTTPClient struct { | ||||||
| // to customize how the client is mocked. | // to customize how the client is mocked. | ||||||
| // | // | ||||||
| // Note that you should never ever make ACTUAL http calls with this thing. | // Note that you should never ever make ACTUAL http calls with this thing. | ||||||
| func NewMockHTTPClient(do func(req *http.Request) (*http.Response, error), relativeMediaPath string, extraPeople ...vocab.ActivityStreamsPerson) *MockHTTPClient { | func NewMockHTTPClient(do func(req *http.Request) (*http.Response, error), relativeMediaPath string, extraPeople ...ap.Accountable) *MockHTTPClient { | ||||||
| 	mockHTTPClient := &MockHTTPClient{} | 	mockHTTPClient := &MockHTTPClient{} | ||||||
| 
 | 
 | ||||||
| 	if do != nil { | 	if do != nil { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue