mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-01-27 11:06:36 +01: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
|
||||
|
||||
## `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
|
||||
|
||||
GoToSocial implements Inboxes for Actors following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#inbox).
|
||||
|
|
|
@ -17,6 +17,22 @@
|
|||
|
||||
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
|
||||
const (
|
||||
ActivityAccept = "Accept" // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"io"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/activity/pub"
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
|
@ -111,7 +110,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can like.
|
||||
canLikeAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canLikeAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canLikeAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canLike.SetGoToSocialAlways(canLikeAlwaysProp)
|
||||
|
||||
// Empty approvalRequired.
|
||||
|
@ -128,7 +127,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Anyone can reply.
|
||||
canReplyAlwaysProp := streams.NewGoToSocialAlwaysProperty()
|
||||
canReplyAlwaysProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canReplyAlwaysProp.AppendIRI(ap.PublicURI())
|
||||
canReply.SetGoToSocialAlways(canReplyAlwaysProp)
|
||||
|
||||
// Set empty approvalRequired.
|
||||
|
@ -151,7 +150,7 @@ func noteWithMentions1() vocab.ActivityStreamsNote {
|
|||
|
||||
// Public requires approval to announce.
|
||||
canAnnounceApprovalRequiredProp := streams.NewGoToSocialApprovalRequiredProperty()
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
canAnnounceApprovalRequiredProp.AppendIRI(ap.PublicURI())
|
||||
canAnnounce.SetGoToSocialApprovalRequired(canAnnounceApprovalRequiredProp)
|
||||
|
||||
// Set canAnnounce on the policy.
|
||||
|
@ -266,7 +265,7 @@ func addressable1() ap.Addressable {
|
|||
note := streams.NewActivityStreamsNote()
|
||||
|
||||
toProp := streams.NewActivityStreamsToProperty()
|
||||
toProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
toProp.AppendIRI(ap.PublicURI())
|
||||
|
||||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
|
@ -288,7 +287,7 @@ func addressable2() ap.Addressable {
|
|||
note.SetActivityStreamsTo(toProp)
|
||||
|
||||
ccProp := streams.NewActivityStreamsCcProperty()
|
||||
ccProp.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
ccProp.AppendIRI(ap.PublicURI())
|
||||
|
||||
note.SetActivityStreamsCc(ccProp)
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@ type Accountable interface {
|
|||
WithTag
|
||||
WithPublished
|
||||
WithUpdated
|
||||
WithImage
|
||||
}
|
||||
|
||||
// Statusable represents the minimum activitypub interface for representing a 'status'.
|
||||
|
@ -439,6 +440,7 @@ type WithValue interface {
|
|||
// WithImage represents an activity with ActivityStreamsImageProperty
|
||||
type WithImage interface {
|
||||
GetActivityStreamsImage() vocab.ActivityStreamsImageProperty
|
||||
SetActivityStreamsImage(vocab.ActivityStreamsImageProperty)
|
||||
}
|
||||
|
||||
// WithSummary represents an activity with ActivityStreamsSummaryProperty
|
||||
|
|
|
@ -177,38 +177,6 @@ func (suite *InboxPostTestSuite) newUndo(
|
|||
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 {
|
||||
// create a delete
|
||||
delete := streams.NewActivityStreamsDelete()
|
||||
|
@ -225,7 +193,7 @@ func (suite *InboxPostTestSuite) newDelete(actorIRI string, objectIRI string, de
|
|||
|
||||
// Set the To of the delete as public
|
||||
deleteTo := streams.NewActivityStreamsToProperty()
|
||||
deleteTo.AppendIRI(testrig.URLMustParse(pub.PublicActivityPubIRI))
|
||||
deleteTo.AppendIRI(ap.PublicURI())
|
||||
delete.SetActivityStreamsTo(deleteTo)
|
||||
|
||||
// set some random-ass ID for the activity
|
||||
|
@ -329,7 +297,6 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
var (
|
||||
requestingAccount = new(gtsmodel.Account)
|
||||
targetAccount = suite.testAccounts["local_account_1"]
|
||||
activityID = "http://fossbros-anonymous.io/72cc96a3-f742-4daf-b9f5-3407667260c5"
|
||||
updatedDisplayName = "updated display name!"
|
||||
)
|
||||
|
||||
|
@ -348,11 +315,19 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
requestingAccount.Emojis = []*gtsmodel.Emoji{testEmoji}
|
||||
|
||||
// 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 {
|
||||
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.
|
||||
suite.inboxPost(
|
||||
|
@ -540,17 +515,20 @@ func (suite *InboxPostTestSuite) TestPostFromBlockedAccount() {
|
|||
var (
|
||||
requestingAccount = suite.testAccounts["remote_account_1"]
|
||||
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 {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
// Post an update from foss satan to turtle, who blocks him.
|
||||
update := suite.newUpdatePerson(person, targetAccount.URI, activityID)
|
||||
|
||||
// Post an update from foss satan
|
||||
// to turtle, who blocks him.
|
||||
suite.inboxPost(
|
||||
update,
|
||||
requestingAccount,
|
||||
|
|
|
@ -75,12 +75,12 @@ func (suite *FederatorStandardTestSuite) SetupTest() {
|
|||
|
||||
// Ensure it's possible to deref
|
||||
// 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 {
|
||||
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.TestRemoteStatuses = testrig.NewTestFediStatuses()
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"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.
|
||||
person, err := p.converter.AccountToAS(ctx, receiver)
|
||||
accountable, err := p.converter.AccountToAS(ctx, receiver)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error converting account: %w", 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
|
||||
// yours' situation, where we sort of agree to reveal each
|
||||
// other's profiles at the same time.
|
||||
return data(person)
|
||||
return data(accountable)
|
||||
}
|
||||
|
||||
// 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 data(person)
|
||||
return data(accountable)
|
||||
}
|
||||
|
||||
func data(requestedPerson vocab.ActivityStreamsPerson) (interface{}, gtserror.WithCode) {
|
||||
data, err := ap.Serialize(requestedPerson)
|
||||
func data(accountable ap.Accountable) (interface{}, gtserror.WithCode) {
|
||||
data, err := ap.Serialize(accountable)
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error serializing person: %w", err)
|
||||
err := gtserror.Newf("error serializing accountable: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
"context"
|
||||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/activity/pub"
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
|
@ -93,11 +92,6 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account)
|
|||
return err
|
||||
}
|
||||
|
||||
publicIRI, err := parseURI(pub.PublicActivityPubIRI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a new delete.
|
||||
// todo: tc.AccountToASDelete
|
||||
delete := streams.NewActivityStreamsDelete()
|
||||
|
@ -121,7 +115,7 @@ func (f *federate) DeleteAccount(ctx context.Context, account *gtsmodel.Account)
|
|||
|
||||
// Address the delete CC public.
|
||||
deleteCC := streams.NewActivityStreamsCcProperty()
|
||||
deleteCC.AppendIRI(publicIRI)
|
||||
deleteCC.AppendIRI(ap.PublicURI())
|
||||
delete.SetActivityStreamsCc(deleteCC)
|
||||
|
||||
// Send the Delete via the Actor's outbox.
|
||||
|
@ -877,14 +871,14 @@ func (f *federate) UpdateAccount(ctx context.Context, account *gtsmodel.Account)
|
|||
return err
|
||||
}
|
||||
|
||||
// Convert account to ActivityStreams Person.
|
||||
person, err := f.converter.AccountToAS(ctx, account)
|
||||
// Convert account to Accountable.
|
||||
accountable, err := f.converter.AccountToAS(ctx, account)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error converting account to Person: %w", err)
|
||||
}
|
||||
|
||||
// Use ActivityStreams Person as Object of Update.
|
||||
update, err := f.converter.WrapPersonInUpdate(person, account)
|
||||
// Use Accountable as Object of Update.
|
||||
update, err := f.converter.WrapAccountableInUpdate(accountable)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
publicIRI, err := parseURI(pub.PublicActivityPubIRI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a new move.
|
||||
move := streams.NewActivityStreamsMove()
|
||||
|
||||
|
@ -1115,7 +1104,7 @@ func (f *federate) MoveAccount(ctx context.Context, account *gtsmodel.Account) e
|
|||
ap.AppendTo(move, followersIRI)
|
||||
|
||||
// Address the move CC public.
|
||||
ap.AppendCc(move, publicIRI)
|
||||
ap.AppendCc(move, ap.PublicURI())
|
||||
|
||||
// Send the Move via the Actor's outbox.
|
||||
if _, err := f.FederatingActor().Send(
|
||||
|
|
|
@ -36,12 +36,24 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/uris"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util/xslices"
|
||||
)
|
||||
|
||||
// AccountToAS converts a gts model account into an activity streams person, suitable for federation
|
||||
func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab.ActivityStreamsPerson, error) {
|
||||
person := streams.NewActivityStreamsPerson()
|
||||
// AccountToAS converts a gts model account
|
||||
// into an activity streams person or service.
|
||||
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
|
||||
// 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.SetIRI(profileIDURI)
|
||||
person.SetJSONLDId(idProp)
|
||||
accountable.SetJSONLDId(idProp)
|
||||
|
||||
// published
|
||||
// The moment when the account was created.
|
||||
publishedProp := streams.NewActivityStreamsPublishedProperty()
|
||||
publishedProp.Set(a.CreatedAt)
|
||||
person.SetActivityStreamsPublished(publishedProp)
|
||||
accountable.SetActivityStreamsPublished(publishedProp)
|
||||
|
||||
// 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.SetIRI(followingURI)
|
||||
person.SetActivityStreamsFollowing(followingProp)
|
||||
accountable.SetActivityStreamsFollowing(followingProp)
|
||||
|
||||
// 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.SetIRI(followersURI)
|
||||
person.SetActivityStreamsFollowers(followersProp)
|
||||
accountable.SetActivityStreamsFollowers(followersProp)
|
||||
|
||||
// inbox
|
||||
// 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.SetIRI(inboxURI)
|
||||
person.SetActivityStreamsInbox(inboxProp)
|
||||
accountable.SetActivityStreamsInbox(inboxProp)
|
||||
|
||||
// shared inbox -- only add this if we know for sure it has one
|
||||
if a.SharedInboxURI != nil && *a.SharedInboxURI != "" {
|
||||
|
@ -101,7 +113,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
sharedInboxProp.SetIRI(sharedInboxURI)
|
||||
endpoints.SetActivityStreamsSharedInbox(sharedInboxProp)
|
||||
endpointsProp.AppendActivityStreamsEndpoints(endpoints)
|
||||
person.SetActivityStreamsEndpoints(endpointsProp)
|
||||
accountable.SetActivityStreamsEndpoints(endpointsProp)
|
||||
}
|
||||
|
||||
// outbox
|
||||
|
@ -112,7 +124,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
}
|
||||
outboxProp := streams.NewActivityStreamsOutboxProperty()
|
||||
outboxProp.SetIRI(outboxURI)
|
||||
person.SetActivityStreamsOutbox(outboxProp)
|
||||
accountable.SetActivityStreamsOutbox(outboxProp)
|
||||
|
||||
// featured posts
|
||||
// Pinned posts.
|
||||
|
@ -122,7 +134,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
}
|
||||
featuredProp := streams.NewTootFeaturedProperty()
|
||||
featuredProp.SetIRI(featuredURI)
|
||||
person.SetTootFeatured(featuredProp)
|
||||
accountable.SetTootFeatured(featuredProp)
|
||||
|
||||
// featuredTags
|
||||
// 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.
|
||||
preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty()
|
||||
preferredUsernameProp.SetXMLSchemaString(a.Username)
|
||||
person.SetActivityStreamsPreferredUsername(preferredUsernameProp)
|
||||
accountable.SetActivityStreamsPreferredUsername(preferredUsernameProp)
|
||||
|
||||
// name
|
||||
// Used as profile display name.
|
||||
|
@ -141,14 +153,14 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
} else {
|
||||
nameProp.AppendXMLSchemaString(a.Username)
|
||||
}
|
||||
person.SetActivityStreamsName(nameProp)
|
||||
accountable.SetActivityStreamsName(nameProp)
|
||||
|
||||
// summary
|
||||
// Used as profile bio.
|
||||
if a.Note != "" {
|
||||
summaryProp := streams.NewActivityStreamsSummaryProperty()
|
||||
summaryProp.AppendXMLSchemaString(a.Note)
|
||||
person.SetActivityStreamsSummary(summaryProp)
|
||||
accountable.SetActivityStreamsSummary(summaryProp)
|
||||
}
|
||||
|
||||
// url
|
||||
|
@ -159,19 +171,19 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
}
|
||||
urlProp := streams.NewActivityStreamsUrlProperty()
|
||||
urlProp.AppendIRI(profileURL)
|
||||
person.SetActivityStreamsUrl(urlProp)
|
||||
accountable.SetActivityStreamsUrl(urlProp)
|
||||
|
||||
// manuallyApprovesFollowers
|
||||
// Will be shown as a locked account.
|
||||
manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty()
|
||||
manuallyApprovesFollowersProp.Set(*a.Locked)
|
||||
person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp)
|
||||
accountable.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp)
|
||||
|
||||
// discoverable
|
||||
// Will be shown in the profile directory.
|
||||
discoverableProp := streams.NewTootDiscoverableProperty()
|
||||
discoverableProp.Set(*a.Discoverable)
|
||||
person.SetTootDiscoverable(discoverableProp)
|
||||
accountable.SetTootDiscoverable(discoverableProp)
|
||||
|
||||
// devices
|
||||
// NOT IMPLEMENTED, probably won't implement
|
||||
|
@ -189,7 +201,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
alsoKnownAsURIs[i] = uri
|
||||
}
|
||||
|
||||
ap.SetAlsoKnownAs(person, alsoKnownAsURIs)
|
||||
ap.SetAlsoKnownAs(accountable, alsoKnownAsURIs)
|
||||
}
|
||||
|
||||
// movedTo
|
||||
|
@ -200,7 +212,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ap.SetMovedTo(person, movedTo)
|
||||
ap.SetMovedTo(accountable, movedTo)
|
||||
}
|
||||
|
||||
// publicKey
|
||||
|
@ -241,7 +253,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey)
|
||||
|
||||
// set the public key property on the Person
|
||||
person.SetW3IDSecurityV1PublicKey(publicKeyProp)
|
||||
accountable.SetW3IDSecurityV1PublicKey(publicKeyProp)
|
||||
|
||||
// tags
|
||||
tagProp := streams.NewActivityStreamsTagProperty()
|
||||
|
@ -269,7 +281,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
// tag -- hashtags
|
||||
// TODO
|
||||
|
||||
person.SetActivityStreamsTag(tagProp)
|
||||
accountable.SetActivityStreamsTag(tagProp)
|
||||
|
||||
// attachment
|
||||
// Used for profile fields.
|
||||
|
@ -290,7 +302,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
attachmentProp.AppendSchemaPropertyValue(propertyValue)
|
||||
}
|
||||
|
||||
person.SetActivityStreamsAttachment(attachmentProp)
|
||||
accountable.SetActivityStreamsAttachment(attachmentProp)
|
||||
}
|
||||
|
||||
// endpoints
|
||||
|
@ -326,7 +338,7 @@ func (c *Converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
|
|||
iconImage.SetActivityStreamsUrl(avatarURLProperty)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
// suitable for serving to requesters to whom we want to give as little information as possible because
|
||||
// we don't trust them (yet).
|
||||
func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account) (vocab.ActivityStreamsPerson, error) {
|
||||
person := streams.NewActivityStreamsPerson()
|
||||
// The returned account will just have the Type, Username,
|
||||
// PublicKey, and ID properties set. This is suitable for
|
||||
// serving to requesters to whom we want to give as little
|
||||
// information as possible because we don't trust them (yet).
|
||||
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
|
||||
// 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.SetIRI(profileIDURI)
|
||||
person.SetJSONLDId(idProp)
|
||||
accountable.SetJSONLDId(idProp)
|
||||
|
||||
// preferredUsername
|
||||
// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI.
|
||||
preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty()
|
||||
preferredUsernameProp.SetXMLSchemaString(a.Username)
|
||||
person.SetActivityStreamsPreferredUsername(preferredUsernameProp)
|
||||
accountable.SetActivityStreamsPreferredUsername(preferredUsernameProp)
|
||||
|
||||
// publicKey
|
||||
// Required for signatures.
|
||||
|
@ -429,9 +453,9 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account)
|
|||
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey)
|
||||
|
||||
// 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
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
||||
|
@ -38,10 +39,10 @@ func (suite *InternalToASTestSuite) TestAccountToAS() {
|
|||
testAccount := >smodel.Account{}
|
||||
*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)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
|
@ -94,14 +95,80 @@ func (suite *InternalToASTestSuite) TestAccountToAS() {
|
|||
}`, 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() {
|
||||
testAccount := >smodel.Account{}
|
||||
*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)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
|
@ -176,10 +243,10 @@ func (suite *InternalToASTestSuite) TestAccountToASAliasedAndMoved() {
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
|
||||
accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
|
@ -246,10 +313,10 @@ func (suite *InternalToASTestSuite) TestAccountToASWithOneField() {
|
|||
*testAccount = *suite.testAccounts["local_account_2"]
|
||||
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)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
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.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)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
|
@ -381,10 +448,10 @@ func (suite *InternalToASTestSuite) TestAccountToASWithSharedInbox() {
|
|||
sharedInbox := "http://localhost:8080/sharedInbox"
|
||||
testAccount.SharedInboxURI = &sharedInbox
|
||||
|
||||
asPerson, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
|
||||
accountable, err := suite.typeconverter.AccountToAS(context.Background(), testAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
ser, err := ap.Serialize(asPerson)
|
||||
ser, err := ap.Serialize(accountable)
|
||||
suite.NoError(err)
|
||||
|
||||
bytes, err := json.MarshalIndent(ser, "", " ")
|
||||
|
|
|
@ -18,68 +18,45 @@
|
|||
package typeutils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/activity/pub"
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"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/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/uris"
|
||||
)
|
||||
|
||||
// WrapPersonInUpdate ...
|
||||
func (c *Converter) WrapPersonInUpdate(person vocab.ActivityStreamsPerson, originAccount *gtsmodel.Account) (vocab.ActivityStreamsUpdate, error) {
|
||||
// WrapAccountableInUpdate wraps the given accountable
|
||||
// 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()
|
||||
|
||||
// set the actor
|
||||
actorURI, err := url.Parse(originAccount.URI)
|
||||
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 actor IRI to this accountable's IRI.
|
||||
ap.AppendActorIRIs(update, ap.GetJSONLDId(accountable))
|
||||
|
||||
// set the ID
|
||||
newID, err := id.NewRandomULID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Set the update ID
|
||||
updateURI := uris.GenerateURIForUpdate(ap.ExtractPreferredUsername(accountable), id.NewULID())
|
||||
ap.MustSet(ap.SetJSONLDIdStr, ap.WithJSONLDId(update), updateURI)
|
||||
|
||||
idString := uris.GenerateURIForUpdate(originAccount.Username, newID)
|
||||
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
|
||||
// Set the accountable as the object of the update.
|
||||
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)
|
||||
|
||||
// to should be public
|
||||
toURI, err := url.Parse(pub.PublicActivityPubIRI)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error parsing url %s: %w", pub.PublicActivityPubIRI, err)
|
||||
}
|
||||
toProp := streams.NewActivityStreamsToProperty()
|
||||
toProp.AppendIRI(toURI)
|
||||
update.SetActivityStreamsTo(toProp)
|
||||
// to should be public.
|
||||
ap.AppendTo(update, ap.PublicURI())
|
||||
|
||||
// bcc followers
|
||||
followersURI, err := url.Parse(originAccount.FollowersURI)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error parsing url %s: %w", originAccount.FollowersURI, err)
|
||||
}
|
||||
bccProp := streams.NewActivityStreamsBccProperty()
|
||||
bccProp.AppendIRI(followersURI)
|
||||
update.SetActivityStreamsBcc(bccProp)
|
||||
// bcc should be followers.
|
||||
ap.AppendBcc(update, ap.GetFollowers(accountable))
|
||||
|
||||
return update, nil
|
||||
}
|
||||
|
|
|
@ -139,6 +139,86 @@ func (suite *WrapTestSuite) TestWrapNoteInCreate() {
|
|||
}`, 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) {
|
||||
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!",
|
||||
"",
|
||||
URLMustParse("http://example.org/users/Some_User"),
|
||||
[]*url.URL{URLMustParse(pub.PublicActivityPubIRI)},
|
||||
[]*url.URL{ap.PublicURI()},
|
||||
nil,
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{},
|
||||
|
@ -3207,7 +3207,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"this is a public status, please forward it!",
|
||||
"",
|
||||
URLMustParse("http://example.org/users/Some_User"),
|
||||
[]*url.URL{URLMustParse(pub.PublicActivityPubIRI)},
|
||||
[]*url.URL{ap.PublicURI()},
|
||||
nil,
|
||||
false,
|
||||
[]vocab.ActivityStreamsMention{},
|
||||
|
@ -3228,7 +3228,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
URLMustParse(pub.PublicActivityPubIRI),
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
|
@ -3244,7 +3244,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
URLMustParse(pub.PublicActivityPubIRI),
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
|
@ -3265,7 +3265,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"",
|
||||
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
|
||||
[]*url.URL{
|
||||
URLMustParse(pub.PublicActivityPubIRI),
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
|
@ -3286,7 +3286,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"",
|
||||
URLMustParse("https://turnip.farm/users/turniplover6969"),
|
||||
[]*url.URL{
|
||||
URLMustParse(pub.PublicActivityPubIRI),
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
|
@ -3309,7 +3309,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
|
|||
"",
|
||||
URLMustParse("http://fossbros-anonymous.io/users/foss_satan"),
|
||||
[]*url.URL{
|
||||
URLMustParse(pub.PublicActivityPubIRI),
|
||||
ap.PublicURI(),
|
||||
},
|
||||
[]*url.URL{},
|
||||
false,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"github.com/superseriousbusiness/activity/pub"
|
||||
"github.com/superseriousbusiness/activity/streams"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/federation"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
|
@ -81,7 +82,7 @@ type MockHTTPClient struct {
|
|||
// to customize how the client is mocked.
|
||||
//
|
||||
// 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{}
|
||||
|
||||
if do != nil {
|
||||
|
|
Loading…
Reference in a new issue