mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-27 19:01:01 +00:00
[chore] Add test for dereferencing Owncast service account (#613)
This commit is contained in:
parent
1cdc163276
commit
dc8cc7e364
5 changed files with 344 additions and 0 deletions
|
@ -51,6 +51,26 @@ func (suite *AccountTestSuite) TestDereferenceGroup() {
|
|||
suite.Equal(ap.ActorGroup, dbGroup.ActorType)
|
||||
}
|
||||
|
||||
func (suite *AccountTestSuite) TestDereferenceService() {
|
||||
fetchingAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
serviceURL := testrig.URLMustParse("https://owncast.example.org/federation/user/rgh")
|
||||
service, err := suite.dereferencer.GetRemoteAccount(context.Background(), fetchingAccount.Username, serviceURL, false, false)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(service)
|
||||
suite.NotNil(service)
|
||||
|
||||
// service values should be set
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh", service.URI)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh", service.URL)
|
||||
|
||||
// service should be in the database
|
||||
dbService, err := suite.db.GetAccountByURI(context.Background(), service.URI)
|
||||
suite.NoError(err)
|
||||
suite.Equal(service.ID, dbService.ID)
|
||||
suite.Equal(ap.ActorService, dbService.ActorType)
|
||||
}
|
||||
|
||||
func TestAccountTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AccountTestSuite))
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ type DereferencerStandardTestSuite struct {
|
|||
testRemoteStatuses map[string]vocab.ActivityStreamsNote
|
||||
testRemotePeople map[string]vocab.ActivityStreamsPerson
|
||||
testRemoteGroups map[string]vocab.ActivityStreamsGroup
|
||||
testRemoteServices map[string]vocab.ActivityStreamsService
|
||||
testRemoteAttachments map[string]testrig.RemoteAttachmentFile
|
||||
testAccounts map[string]*gtsmodel.Account
|
||||
|
||||
|
@ -60,6 +61,7 @@ func (suite *DereferencerStandardTestSuite) SetupTest() {
|
|||
suite.testRemoteStatuses = testrig.NewTestFediStatuses()
|
||||
suite.testRemotePeople = testrig.NewTestFediPeople()
|
||||
suite.testRemoteGroups = testrig.NewTestFediGroups()
|
||||
suite.testRemoteServices = testrig.NewTestFediServices()
|
||||
suite.testRemoteAttachments = testrig.NewTestFediAttachments("../../../testrig/media")
|
||||
|
||||
suite.db = testrig.NewTestDB()
|
||||
|
@ -126,6 +128,19 @@ func (suite *DereferencerStandardTestSuite) mockTransportController() transport.
|
|||
responseType = "application/activity+json"
|
||||
}
|
||||
|
||||
if service, ok := suite.testRemoteServices[req.URL.String()]; ok {
|
||||
serviceI, err := streams.Serialize(service)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serviceJson, err := json.Marshal(serviceI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
responseBytes = serviceJson
|
||||
responseType = "application/activity+json"
|
||||
}
|
||||
|
||||
if attachment, ok := suite.testRemoteAttachments[req.URL.String()]; ok {
|
||||
responseBytes = attachment.Data
|
||||
responseType = attachment.ContentType
|
||||
|
|
|
@ -157,6 +157,49 @@ func (suite *ASToInternalTestSuite) TestParseReplyWithMention() {
|
|||
suite.Equal(gtsmodel.VisibilityUnlocked, status.Visibility)
|
||||
}
|
||||
|
||||
func (suite *ASToInternalTestSuite) TestParseOwncastService() {
|
||||
m := make(map[string]interface{})
|
||||
err := json.Unmarshal([]byte(owncastService), &m)
|
||||
suite.NoError(err)
|
||||
|
||||
t, err := streams.ToType(context.Background(), m)
|
||||
suite.NoError(err)
|
||||
|
||||
rep, ok := t.(ap.Accountable)
|
||||
suite.True(ok)
|
||||
|
||||
acct, err := suite.typeconverter.ASRepresentationToAccount(context.Background(), rep, false)
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal("rgh", acct.Username)
|
||||
suite.Equal("owncast.example.org", acct.Domain)
|
||||
suite.Equal("https://owncast.example.org/logo/external", acct.AvatarRemoteURL)
|
||||
suite.Equal("https://owncast.example.org/logo/external", acct.HeaderRemoteURL)
|
||||
suite.Equal("Rob's Owncast Server", acct.DisplayName)
|
||||
suite.Equal("linux audio stuff ", acct.Note)
|
||||
suite.True(acct.Bot)
|
||||
suite.False(acct.Locked)
|
||||
suite.True(acct.Discoverable)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URI)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URL)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh/inbox", acct.InboxURI)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh/outbox", acct.OutboxURI)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh/followers", acct.FollowersURI)
|
||||
suite.Equal("Service", acct.ActorType)
|
||||
suite.Equal("https://owncast.example.org/federation/user/rgh#main-key", acct.PublicKeyURI)
|
||||
|
||||
acct.ID = "01G42D57DTCJQE8XT9KD4K88RK"
|
||||
|
||||
apiAcct, err := suite.typeconverter.AccountToAPIAccountPublic(context.Background(), acct)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(apiAcct)
|
||||
|
||||
b, err := json.Marshal(apiAcct)
|
||||
suite.NoError(err)
|
||||
|
||||
fmt.Printf("\n\n\n%s\n\n\n", string(b))
|
||||
}
|
||||
|
||||
func TestASToInternalTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(ASToInternalTestSuite))
|
||||
}
|
||||
|
|
|
@ -414,6 +414,57 @@ const (
|
|||
}
|
||||
}
|
||||
`
|
||||
owncastService = `
|
||||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"http://joinmastodon.org/ns",
|
||||
"https://w3id.org/security/v1"
|
||||
],
|
||||
"attachment": {
|
||||
"name": "Stream",
|
||||
"type": "PropertyValue",
|
||||
"value": "<a href=\"https://owncast.example.org\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\">https://owncast.example.org</a>"
|
||||
},
|
||||
"discoverable": true,
|
||||
"followers": "https://owncast.example.org/federation/user/rgh/followers",
|
||||
"icon": {
|
||||
"type": "Image",
|
||||
"url": "https://owncast.example.org/logo/external"
|
||||
},
|
||||
"id": "https://owncast.example.org/federation/user/rgh",
|
||||
"image": {
|
||||
"type": "Image",
|
||||
"url": "https://owncast.example.org/logo/external"
|
||||
},
|
||||
"inbox": "https://owncast.example.org/federation/user/rgh/inbox",
|
||||
"manuallyApprovesFollowers": false,
|
||||
"name": "Rob's Owncast Server",
|
||||
"outbox": "https://owncast.example.org/federation/user/rgh/outbox",
|
||||
"preferredUsername": "rgh",
|
||||
"publicKey": {
|
||||
"id": "https://owncast.example.org/federation/user/rgh#main-key",
|
||||
"owner": "https://owncast.example.org/federation/user/rgh",
|
||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAurN+lUNwcGV2poLNtaoT\naRtJzN6s4SDcBmIFk82lxhdMKC6/Nssm+hvDuxWGqL0+dHwSvrG11rA6irGuSzRk\niHjYyVwYe/p1CxqJxzUfZVJAWdsCFWy+HtDrTWs5sggj1MiL59uGxvkCep+OYBuG\nBI8CvSOMLrDp8soCg3EY+zSgpXtGMuRaaUukavsfuglApShB61ny7W8LG252iKC5\nmyO8L7l8TNa5BrIi/pRHLzvv9aWiCa8VKtvmqj+mClEhpkRhImSk5GPJXgouTTgl\ntT28NYYciSf9YYgZ0SNWHdLUCdkMF592j4+BbkPvdgzc70G4yyu2GcWnTzBuvF5X\nYwIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||
},
|
||||
"published": "2022-05-22T18:44:57Z",
|
||||
"summary": "linux audio stuff ",
|
||||
"tag": [
|
||||
{
|
||||
"href": "https://directory.owncast.online/tags/owncast",
|
||||
"name": "#owncast",
|
||||
"type": "Hashtag"
|
||||
},
|
||||
{
|
||||
"href": "https://directory.owncast.online/tags/streaming",
|
||||
"name": "#streaming",
|
||||
"type": "Hashtag"
|
||||
}
|
||||
],
|
||||
"type": "Service",
|
||||
"url": "https://owncast.example.org/federation/user/rgh"
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
type TypeUtilsTestSuite struct {
|
||||
|
|
|
@ -1821,6 +1821,37 @@ func NewTestFediGroups() map[string]vocab.ActivityStreamsGroup {
|
|||
}
|
||||
}
|
||||
|
||||
func NewTestFediServices() map[string]vocab.ActivityStreamsService {
|
||||
newService1Priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newService1Pub := &newService1Priv.PublicKey
|
||||
|
||||
return map[string]vocab.ActivityStreamsService{
|
||||
"https://owncast.example.org/federation/user/rgh": newAPService(
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh"),
|
||||
nil,
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh/followers"),
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh/inbox"),
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh/outbox"),
|
||||
nil,
|
||||
"rgh",
|
||||
"linux audio stuff ",
|
||||
"",
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh"),
|
||||
true,
|
||||
URLMustParse("https://owncast.example.org/federation/user/rgh#main-key"),
|
||||
newService1Pub,
|
||||
nil,
|
||||
"image/jpeg",
|
||||
nil,
|
||||
"image/png",
|
||||
false,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// RemoteAttachmentFile mimics a remote (federated) attachment
|
||||
type RemoteAttachmentFile struct {
|
||||
Data []byte
|
||||
|
@ -2459,6 +2490,190 @@ func newAPGroup(
|
|||
return group
|
||||
}
|
||||
|
||||
func newAPService(
|
||||
profileIDURI *url.URL,
|
||||
followingURI *url.URL,
|
||||
followersURI *url.URL,
|
||||
inboxURI *url.URL,
|
||||
outboxURI *url.URL,
|
||||
featuredURI *url.URL,
|
||||
username string,
|
||||
displayName string,
|
||||
note string,
|
||||
profileURL *url.URL,
|
||||
discoverable bool,
|
||||
publicKeyURI *url.URL,
|
||||
pkey *rsa.PublicKey,
|
||||
avatarURL *url.URL,
|
||||
avatarContentType string,
|
||||
headerURL *url.URL,
|
||||
headerContentType string,
|
||||
manuallyApprovesFollowers bool,
|
||||
) vocab.ActivityStreamsService {
|
||||
service := streams.NewActivityStreamsService()
|
||||
|
||||
// id should be the activitypub URI of this group
|
||||
// something like https://example.org/users/example_group
|
||||
idProp := streams.NewJSONLDIdProperty()
|
||||
idProp.SetIRI(profileIDURI)
|
||||
service.SetJSONLDId(idProp)
|
||||
|
||||
// following
|
||||
// The URI for retrieving a list of accounts this group is following
|
||||
followingProp := streams.NewActivityStreamsFollowingProperty()
|
||||
followingProp.SetIRI(followingURI)
|
||||
service.SetActivityStreamsFollowing(followingProp)
|
||||
|
||||
// followers
|
||||
// The URI for retrieving a list of this user's followers
|
||||
followersProp := streams.NewActivityStreamsFollowersProperty()
|
||||
followersProp.SetIRI(followersURI)
|
||||
service.SetActivityStreamsFollowers(followersProp)
|
||||
|
||||
// inbox
|
||||
// the activitypub inbox of this user for accepting messages
|
||||
inboxProp := streams.NewActivityStreamsInboxProperty()
|
||||
inboxProp.SetIRI(inboxURI)
|
||||
service.SetActivityStreamsInbox(inboxProp)
|
||||
|
||||
// outbox
|
||||
// the activitypub outbox of this user for serving messages
|
||||
outboxProp := streams.NewActivityStreamsOutboxProperty()
|
||||
outboxProp.SetIRI(outboxURI)
|
||||
service.SetActivityStreamsOutbox(outboxProp)
|
||||
|
||||
// featured posts
|
||||
// Pinned posts.
|
||||
featuredProp := streams.NewTootFeaturedProperty()
|
||||
featuredProp.SetIRI(featuredURI)
|
||||
service.SetTootFeatured(featuredProp)
|
||||
|
||||
// featuredTags
|
||||
// NOT IMPLEMENTED
|
||||
|
||||
// preferredUsername
|
||||
// Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI.
|
||||
preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty()
|
||||
preferredUsernameProp.SetXMLSchemaString(username)
|
||||
service.SetActivityStreamsPreferredUsername(preferredUsernameProp)
|
||||
|
||||
// name
|
||||
// Used as profile display name.
|
||||
nameProp := streams.NewActivityStreamsNameProperty()
|
||||
if displayName != "" {
|
||||
nameProp.AppendXMLSchemaString(displayName)
|
||||
} else {
|
||||
nameProp.AppendXMLSchemaString(username)
|
||||
}
|
||||
service.SetActivityStreamsName(nameProp)
|
||||
|
||||
// summary
|
||||
// Used as profile bio.
|
||||
if note != "" {
|
||||
summaryProp := streams.NewActivityStreamsSummaryProperty()
|
||||
summaryProp.AppendXMLSchemaString(note)
|
||||
service.SetActivityStreamsSummary(summaryProp)
|
||||
}
|
||||
|
||||
// url
|
||||
// Used as profile link.
|
||||
urlProp := streams.NewActivityStreamsUrlProperty()
|
||||
urlProp.AppendIRI(profileURL)
|
||||
service.SetActivityStreamsUrl(urlProp)
|
||||
|
||||
// manuallyApprovesFollowers
|
||||
manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty()
|
||||
manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers)
|
||||
service.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp)
|
||||
|
||||
// discoverable
|
||||
// Will be shown in the profile directory.
|
||||
discoverableProp := streams.NewTootDiscoverableProperty()
|
||||
discoverableProp.Set(discoverable)
|
||||
service.SetTootDiscoverable(discoverableProp)
|
||||
|
||||
// devices
|
||||
// NOT IMPLEMENTED, probably won't implement
|
||||
|
||||
// alsoKnownAs
|
||||
// Required for Move activity.
|
||||
// TODO: NOT IMPLEMENTED **YET** -- this needs to be added as an activitypub extension to https://github.com/go-fed/activity, see https://github.com/go-fed/activity/tree/master/astool
|
||||
|
||||
// publicKey
|
||||
// Required for signatures.
|
||||
publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty()
|
||||
|
||||
// create the public key
|
||||
publicKey := streams.NewW3IDSecurityV1PublicKey()
|
||||
|
||||
// set ID for the public key
|
||||
publicKeyIDProp := streams.NewJSONLDIdProperty()
|
||||
publicKeyIDProp.SetIRI(publicKeyURI)
|
||||
publicKey.SetJSONLDId(publicKeyIDProp)
|
||||
|
||||
// set owner for the public key
|
||||
publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty()
|
||||
publicKeyOwnerProp.SetIRI(profileIDURI)
|
||||
publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp)
|
||||
|
||||
// set the pem key itself
|
||||
encodedPublicKey, err := x509.MarshalPKIXPublicKey(pkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
publicKeyBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: encodedPublicKey,
|
||||
})
|
||||
publicKeyPEMProp := streams.NewW3IDSecurityV1PublicKeyPemProperty()
|
||||
publicKeyPEMProp.Set(string(publicKeyBytes))
|
||||
publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp)
|
||||
|
||||
// append the public key to the public key property
|
||||
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey)
|
||||
|
||||
// set the public key property on the Person
|
||||
service.SetW3IDSecurityV1PublicKey(publicKeyProp)
|
||||
|
||||
// tag
|
||||
// TODO: Any tags used in the summary of this profile
|
||||
|
||||
// attachment
|
||||
// Used for profile fields.
|
||||
// TODO: The PropertyValue type has to be added: https://schema.org/PropertyValue
|
||||
|
||||
// endpoints
|
||||
// NOT IMPLEMENTED -- this is for shared inbox which we don't use
|
||||
|
||||
// icon
|
||||
// Used as profile avatar.
|
||||
iconProperty := streams.NewActivityStreamsIconProperty()
|
||||
iconImage := streams.NewActivityStreamsImage()
|
||||
mediaType := streams.NewActivityStreamsMediaTypeProperty()
|
||||
mediaType.Set(avatarContentType)
|
||||
iconImage.SetActivityStreamsMediaType(mediaType)
|
||||
avatarURLProperty := streams.NewActivityStreamsUrlProperty()
|
||||
avatarURLProperty.AppendIRI(avatarURL)
|
||||
iconImage.SetActivityStreamsUrl(avatarURLProperty)
|
||||
iconProperty.AppendActivityStreamsImage(iconImage)
|
||||
service.SetActivityStreamsIcon(iconProperty)
|
||||
|
||||
// image
|
||||
// Used as profile header.
|
||||
headerProperty := streams.NewActivityStreamsImageProperty()
|
||||
headerImage := streams.NewActivityStreamsImage()
|
||||
headerMediaType := streams.NewActivityStreamsMediaTypeProperty()
|
||||
mediaType.Set(headerContentType)
|
||||
headerImage.SetActivityStreamsMediaType(headerMediaType)
|
||||
headerURLProperty := streams.NewActivityStreamsUrlProperty()
|
||||
headerURLProperty.AppendIRI(headerURL)
|
||||
headerImage.SetActivityStreamsUrl(headerURLProperty)
|
||||
headerProperty.AppendActivityStreamsImage(headerImage)
|
||||
service.SetActivityStreamsImage(headerProperty)
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
func newAPMention(uri *url.URL, namestring string) vocab.ActivityStreamsMention {
|
||||
mention := streams.NewActivityStreamsMention()
|
||||
|
||||
|
|
Loading…
Reference in a new issue