diff options
author | 2025-01-23 17:18:23 +0000 | |
---|---|---|
committer | 2025-01-23 18:18:23 +0100 | |
commit | 9333bbc4d0d5ae46c72fca1f5b1aacb3c0a7653e (patch) | |
tree | e7ccd1dc3abff5386e0b86e6baf659c9aa3b55a5 /internal/typeutils | |
parent | [feature] Add warning about `trusted-proxies` to make config easier (#3675) (diff) | |
download | gotosocial-9333bbc4d0d5ae46c72fca1f5b1aacb3c0a7653e.tar.xz |
[feature] Serve bot accounts over AP as Service instead of Person (#3672)
* pepis
* oopsie doopsie
* bollocks
Diffstat (limited to 'internal/typeutils')
-rw-r--r-- | internal/typeutils/internaltoas.go | 94 | ||||
-rw-r--r-- | internal/typeutils/internaltoas_test.go | 91 | ||||
-rw-r--r-- | internal/typeutils/wrap.go | 71 | ||||
-rw-r--r-- | internal/typeutils/wrap_test.go | 80 |
4 files changed, 242 insertions, 94 deletions
diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index de1badb5c..ce5187bde 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -36,12 +36,24 @@ import ( "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 diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go index 344a42798..4d0d95641 100644 --- a/internal/typeutils/internaltoas_test.go +++ b/internal/typeutils/internaltoas_test.go @@ -27,6 +27,7 @@ import ( "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, "", " ") diff --git a/internal/typeutils/wrap.go b/internal/typeutils/wrap.go index 89bcdfc09..1230981d4 100644 --- a/internal/typeutils/wrap.go +++ b/internal/typeutils/wrap.go @@ -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 } diff --git a/internal/typeutils/wrap_test.go b/internal/typeutils/wrap_test.go index 1085c8c66..8c8af7506 100644 --- a/internal/typeutils/wrap_test.go +++ b/internal/typeutils/wrap_test.go @@ -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)) } |