// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see
hey yo this is my profile!
", NoteRaw: "hey yo this is my profile!", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"), UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"), Bot: util.Ptr(false), Reason: "I wanna be on this damned webbed site so bad! Please! Wow", Locked: util.Ptr(false), Discoverable: util.Ptr(true), Privacy: gtsmodel.VisibilityPublic, Sensitive: util.Ptr(false), Language: "en", URI: "http://localhost:8080/users/the_mighty_zork", URL: "http://localhost:8080/@the_mighty_zork", FetchedAt: time.Time{}, InboxURI: "http://localhost:8080/users/the_mighty_zork/inbox", OutboxURI: "http://localhost:8080/users/the_mighty_zork/outbox", FollowersURI: "http://localhost:8080/users/the_mighty_zork/followers", FollowingURI: "http://localhost:8080/users/the_mighty_zork/following", FeaturedCollectionURI: "http://localhost:8080/users/the_mighty_zork/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "http://localhost:8080/users/the_mighty_zork/main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", EnableRSS: util.Ptr(true), }, "local_account_2": { ID: "01F8MH5NBDF2MV7CTC4Q5128HF", Username: "1happyturtle", AvatarMediaAttachmentID: "", HeaderMediaAttachmentID: "", DisplayName: "happy little turtle :3", Fields: []*gtsmodel.Field{ { Name: "should you follow me?", Value: "maybe!", }, { Name: "age", Value: "120", }, }, FieldsRaw: []*gtsmodel.Field{ { Name: "should you follow me?", Value: "maybe!", }, { Name: "age", Value: "120", }, }, Note: "i post about things that concern me
", NoteRaw: "i post about things that concern me", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Bot: util.Ptr(false), Reason: "", Locked: util.Ptr(true), Discoverable: util.Ptr(false), Privacy: gtsmodel.VisibilityFollowersOnly, Sensitive: util.Ptr(true), Language: "fr", URI: "http://localhost:8080/users/1happyturtle", URL: "http://localhost:8080/@1happyturtle", FetchedAt: time.Time{}, InboxURI: "http://localhost:8080/users/1happyturtle/inbox", OutboxURI: "http://localhost:8080/users/1happyturtle/outbox", FollowersURI: "http://localhost:8080/users/1happyturtle/followers", FollowingURI: "http://localhost:8080/users/1happyturtle/following", FeaturedCollectionURI: "http://localhost:8080/users/1happyturtle/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "http://localhost:8080/users/1happyturtle#main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", EnableRSS: util.Ptr(false), }, "remote_account_1": { ID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", Username: "foss_satan", Domain: "fossbros-anonymous.io", DisplayName: "big gerald", Fields: []*gtsmodel.Field{}, Note: "i post about like, i dunno, stuff, or whatever!!!!", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2021-09-26T12:52:36+02:00"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Bot: util.Ptr(false), Locked: util.Ptr(false), Discoverable: util.Ptr(true), Sensitive: util.Ptr(false), Language: "en", URI: "http://fossbros-anonymous.io/users/foss_satan", URL: "http://fossbros-anonymous.io/@foss_satan", FetchedAt: time.Time{}, InboxURI: "http://fossbros-anonymous.io/users/foss_satan/inbox", SharedInboxURI: util.Ptr("http://fossbros-anonymous.io/inbox"), OutboxURI: "http://fossbros-anonymous.io/users/foss_satan/outbox", FollowersURI: "http://fossbros-anonymous.io/users/foss_satan/followers", FollowingURI: "http://fossbros-anonymous.io/users/foss_satan/following", FeaturedCollectionURI: "http://fossbros-anonymous.io/users/foss_satan/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "http://fossbros-anonymous.io/users/foss_satan/main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", EnableRSS: util.Ptr(false), }, "remote_account_2": { ID: "01FHMQX3GAABWSM0S2VZEC2SWC", Username: "Some_User", Domain: "example.org", DisplayName: "some user", Fields: []*gtsmodel.Field{}, Note: "i'm a real son of a gun", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Bot: util.Ptr(false), Locked: util.Ptr(true), Discoverable: util.Ptr(true), Sensitive: util.Ptr(false), Language: "en", URI: "http://example.org/users/Some_User", URL: "http://example.org/@Some_User", FetchedAt: time.Time{}, InboxURI: "http://example.org/users/Some_User/inbox", SharedInboxURI: util.Ptr(""), OutboxURI: "http://example.org/users/Some_User/outbox", FollowersURI: "http://example.org/users/Some_User/followers", FollowingURI: "http://example.org/users/Some_User/following", FeaturedCollectionURI: "http://example.org/users/Some_User/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "http://example.org/users/Some_User#main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", EnableRSS: util.Ptr(false), }, "remote_account_3": { ID: "062G5WYKY35KKD12EMSM3F8PJ8", Username: "her_fuckin_maj", Domain: "thequeenisstillalive.technology", DisplayName: "lizzzieeeeeeeeeeee", Fields: []*gtsmodel.Field{}, Note: "if i die blame charles don't let that fuck become king", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Bot: util.Ptr(false), Locked: util.Ptr(true), Discoverable: util.Ptr(true), Sensitive: util.Ptr(false), Language: "en", URI: "http://thequeenisstillalive.technology/users/her_fuckin_maj", URL: "http://thequeenisstillalive.technology/@her_fuckin_maj", FetchedAt: time.Time{}, InboxURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/inbox", SharedInboxURI: util.Ptr(""), OutboxURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/outbox", FollowersURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/followers", FollowingURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/following", FeaturedCollectionURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj#main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3R", EnableRSS: util.Ptr(false), }, "remote_account_4": { ID: "07GZRBAEMBNKGZ8Z9VSKSXKR98", Username: "üser", Domain: "xn--xample-ova.org", DisplayName: "", Note: "", Memorial: util.Ptr(false), MovedToURI: "", CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Bot: util.Ptr(false), Locked: util.Ptr(false), Discoverable: util.Ptr(false), Sensitive: util.Ptr(false), Language: "de", URI: "https://xn--xample-ova.org/users/%C3%BCser", URL: "https://xn--xample-ova.org/users/@%C3%BCser", FetchedAt: time.Time{}, InboxURI: "https://xn--xample-ova.org/users/%C3%BCser/inbox", SharedInboxURI: util.Ptr(""), OutboxURI: "https://xn--xample-ova.org/users/%C3%BCser/outbox", FollowersURI: "https://xn--xample-ova.org/users/%C3%BCser/followers", FollowingURI: "https://xn--xample-ova.org/users/%C3%BCser/following", FeaturedCollectionURI: "https://xn--xample-ova.org/users/%C3%BCser/collections/featured", ActorType: ap.ActorPerson, PrivateKey: &rsa.PrivateKey{}, PublicKey: &rsa.PublicKey{}, PublicKeyURI: "https://xn--xample-ova.org/users/%C3%BCser#main-key", SensitizedAt: time.Time{}, SilencedAt: time.Time{}, SuspendedAt: time.Time{}, HideCollections: util.Ptr(false), SuspensionOrigin: "", HeaderMediaAttachmentID: "", EnableRSS: util.Ptr(false), }, } var accountsSorted []*gtsmodel.Account for _, a := range accounts { accountsSorted = append(accountsSorted, a) } sort.Slice(accountsSorted, func(i, j int) bool { return accountsSorted[i].ID > accountsSorted[j].ID }) preserializedKeys := []string{ "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", } if diff := len(accountsSorted) - len(preserializedKeys); diff > 0 { keyStrings := make([]string, diff) for i := 0; i < diff; i++ { priv, _ := rsa.GenerateKey(rand.Reader, 2048) key, _ := x509.MarshalPKCS8PrivateKey(priv) keyStrings = append(keyStrings, base64.StdEncoding.EncodeToString(key)) } panic(fmt.Sprintf("mismatch between number of hardcoded test RSA keys and accounts used for test data. Insert the following generated key[s]: \n%+v", keyStrings)) } for i, v := range accountsSorted { premadeBytes, err := base64.StdEncoding.DecodeString(preserializedKeys[i]) if err != nil { panic(err) } key, err := x509.ParsePKCS8PrivateKey(premadeBytes) if err != nil { panic(err) } priv, ok := key.(*rsa.PrivateKey) if !ok { panic(fmt.Sprintf("generated key at index %d is of incorrect type", i)) } v.PrivateKey = priv v.PublicKey = &priv.PublicKey } return accounts } func NewTestTombstones() map[string]*gtsmodel.Tombstone { return map[string]*gtsmodel.Tombstone{ "https://somewhere.mysterious/users/rest_in_piss#main-key": { ID: "01GHBTVE9HQPPBDH2W5VH2DGN4", CreatedAt: TimeMustParse("2021-11-09T19:33:45Z"), UpdatedAt: TimeMustParse("2021-11-09T19:33:45Z"), Domain: "somewhere.mysterious", URI: "https://somewhere.mysterious/users/rest_in_piss#main-key", }, } } // NewTestAttachments returns a map of attachments keyed according to which account // and status they belong to, and which attachment number of that status they are. func NewTestAttachments() map[string]*gtsmodel.MediaAttachment { return map[string]*gtsmodel.MediaAttachment{ "admin_account_status_1_attachment_1": { ID: "01F8MH6NEM8D7527KZAECTCR76", StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 1200, Height: 630, Size: 756000, Aspect: 1.9047619047619047, }, Small: gtsmodel.Small{ Width: 256, Height: 134, Size: 34304, Aspect: 1.9104477611940298, }, }, AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", Description: "Black and white image of some 50's style text saying: Welcome On Board", ScheduledStatusID: "", Blurhash: "LNJRdVM{00Rj%Mayt7j[4nWBofRj", Processing: 2, File: gtsmodel.File{ Path: "01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg", ContentType: "image/jpeg", FileSize: 62529, UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg", ContentType: "image/jpeg", FileSize: 6872, UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg", RemoteURL: "", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "local_account_1_status_4_attachment_1": { ID: "01F8MH7TDVANYKWVE8VVKFPJTJ", StatusID: "01F8MH82FYRXD2RC6108DAJ5HB", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH7TDVANYKWVE8VVKFPJTJ.gif", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 400, Height: 280, Size: 756000, Aspect: 1.4285714285714286, }, Small: gtsmodel.Small{ Width: 256, Height: 179, Size: 45824, Aspect: 1.4301675977653632, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Description: "90's Trent Reznor turning to the camera", ScheduledStatusID: "", Blurhash: "LEDara58O=t5EMSOENEN9]}?aK%0", Processing: 2, File: gtsmodel.File{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH7TDVANYKWVE8VVKFPJTJ.gif", ContentType: "image/gif", FileSize: 1109138, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpg", ContentType: "image/jpeg", FileSize: 8803, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpg", RemoteURL: "", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "local_account_1_status_4_attachment_2": { ID: "01CDR64G398ADCHXK08WWTHEZ5", StatusID: "01F8MH82FYRXD2RC6108DAJ5HB", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.mp4", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeVideo, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 720, Height: 404, Size: 290880, Aspect: 1.78217821782178, Duration: util.Ptr[float32](15.033334), Framerate: util.Ptr[float32](30.0), Bitrate: util.Ptr[uint64](1206522), }, Small: gtsmodel.Small{ Width: 720, Height: 404, Size: 290880, Aspect: 1.78217821782178, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Description: "A cow adorably licking another cow!", ScheduledStatusID: "", Blurhash: "", Processing: 2, File: gtsmodel.File{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.gif", ContentType: "video/mp4", FileSize: 2273532, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.jpg", ContentType: "image/jpeg", FileSize: 5272, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.jpg", RemoteURL: "", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "local_account_1_unattached_1": { ID: "01F8MH8RMYQ6MSNY3JM2XT1CQ5", StatusID: "", // this attachment isn't connected to a status YET URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 800, Height: 450, Size: 360000, Aspect: 1.7777777777777777, }, Small: gtsmodel.Small{ Width: 256, Height: 144, Size: 36864, Aspect: 1.7777777777777777, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Description: "the oh you meme", ScheduledStatusID: "", Blurhash: "LSAd]9ogDge-R:M|j=xWIto0xXWX", Processing: 2, File: gtsmodel.File{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", ContentType: "image/jpeg", FileSize: 27759, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", ContentType: "image/jpeg", FileSize: 6177, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", RemoteURL: "", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "local_account_1_avatar": { ID: "01F8MH58A357CV5K7R7TJMSH6S", StatusID: "", // this attachment isn't connected to a status URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 1092, Height: 1800, Size: 1965600, Aspect: 0.6066666666666667, }, Small: gtsmodel.Small{ Width: 155, Height: 256, Size: 39680, Aspect: 0.60546875, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Description: "a green goblin looking nasty", ScheduledStatusID: "", Blurhash: "LKK9MT,p|YSNDkJ-5rsmvnwcOoe:", Processing: 2, File: gtsmodel.File{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg", ContentType: "image/jpeg", FileSize: 457680, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg", ContentType: "image/jpeg", FileSize: 15374, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg", RemoteURL: "", }, Avatar: util.Ptr(true), Header: util.Ptr(false), Cached: util.Ptr(true), }, "local_account_1_header": { ID: "01PFPMWK2FF0D9WMHEJHR07C3Q", StatusID: "", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", RemoteURL: "", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 1018, Height: 764, Size: 777752, Aspect: 1.3324607329842932, }, Small: gtsmodel.Small{ Width: 256, Height: 192, Size: 49152, Aspect: 1.3333333333333333, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Description: "A very old-school screenshot of the original team fortress mod for quake ", ScheduledStatusID: "", Blurhash: "L26j{^WCs+R-N}jsxWj@4;WWxDoK", Processing: 2, File: gtsmodel.File{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", ContentType: "image/jpeg", FileSize: 517226, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", ContentType: "image/jpeg", FileSize: 42308, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", RemoteURL: "", }, Avatar: util.Ptr(false), Header: util.Ptr(true), Cached: util.Ptr(true), }, "remote_account_1_status_1_attachment_1": { ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY0", StatusID: "01FVW7JHQFSFK166WWKR8CBA6M", URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", RemoteURL: "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg", CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 472, Height: 291, Size: 137352, Aspect: 1.6219931271477663, }, Small: gtsmodel.Small{ Width: 472, Height: 291, Size: 137352, Aspect: 1.6219931271477663, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", Description: "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted", ScheduledStatusID: "", Blurhash: "LARysgM_IU_3~pD%M_Rj_39FIAt6", Processing: 2, File: gtsmodel.File{ Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", ContentType: "image/jpeg", FileSize: 19310, UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", ContentType: "image/jpeg", FileSize: 19312, UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "remote_account_3_header": { ID: "01PFPMWK2FF0D9WMHEJHR07C3R", StatusID: "", URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 472, Height: 291, Size: 137352, Aspect: 1.6219931271477663, }, Small: gtsmodel.Small{ Width: 472, Height: 291, Size: 137352, Aspect: 1.6219931271477663, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "062G5WYKY35KKD12EMSM3F8PJ8", Description: "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted", ScheduledStatusID: "", Blurhash: "LARysgM_IU_3~pD%M_Rj_39FIAt6", Processing: 2, File: gtsmodel.File{ Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", ContentType: "image/jpeg", FileSize: 19310, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", ContentType: "image/jpeg", FileSize: 20395, UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", }, Avatar: util.Ptr(false), Header: util.Ptr(true), Cached: util.Ptr(true), }, "remote_account_2_status_1_attachment_1": { ID: "01HE7Y3C432WRSNS10EZM86SA5", StatusID: "01HE7XJ1CG84TBKH5V9XKBVGF5", URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg", RemoteURL: "http://example.org/fileserver/01HE7Y659ZWZ02JM4AWYJZ176Q/attachment/original/01HE7Y6G0EMCKST3Q0914WW0MS.jpg", CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), Type: gtsmodel.FileTypeImage, FileMeta: gtsmodel.FileMeta{ Original: gtsmodel.Original{ Width: 3000, Height: 2000, Size: 6000000, Aspect: 1.5, }, Small: gtsmodel.Small{ Width: 512, Height: 341, Size: 174592, Aspect: 1.5014663, }, Focus: gtsmodel.Focus{ X: 0, Y: 0, }, }, AccountID: "01FHMQX3GAABWSM0S2VZEC2SWC", Description: "Photograph of a sloth, Public Domain.", Blurhash: "LNEC{|w}0K9GsEtPM|j[NFbHoeof", Processing: 2, File: gtsmodel.File{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7Y3C432WRSNS10EZM86SA5.jpg", ContentType: "image/jpg", FileSize: 5450054, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.jpg", ContentType: "image/jpeg", FileSize: 50820, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7Y3C432WRSNS10EZM86SA5.jpg", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(true), }, "remote_account_2_status_1_attachment_2": { ID: "01HE7ZFX9GKA5ZZVD4FACABSS9", StatusID: "01HE7XJ1CG84TBKH5V9XKBVGF5", URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7ZFX9GKA5ZZVD4FACABSS9.svg", RemoteURL: "http://example.org/fileserver/01HE7Y659ZWZ02JM4AWYJZ176Q/attachment/original/01HE7ZGJYTSYMXF927GF9353KR.svg", CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), Type: gtsmodel.FileTypeUnknown, FileMeta: gtsmodel.FileMeta{}, AccountID: "01FHMQX3GAABWSM0S2VZEC2SWC", Description: "SVG line art of a sloth, public domain", Blurhash: "L26*j+~qE1RP?wxut7ofRlM{R*of", Processing: 2, File: gtsmodel.File{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE7ZFX9GKA5ZZVD4FACABSS9.svg", ContentType: "image/svg", FileSize: 147819, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7ZFX9GKA5ZZVD4FACABSS9.jpg", ContentType: "image/jpeg", FileSize: 0, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE7ZFX9GKA5ZZVD4FACABSS9.jpg", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(false), }, "remote_account_2_status_1_attachment_3": { ID: "01HE88YG74PVAB81PX2XA9F3FG", StatusID: "01HE7XJ1CG84TBKH5V9XKBVGF5", URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE88YG74PVAB81PX2XA9F3FG.mp3", RemoteURL: "http://example.org/fileserver/01HE7Y659ZWZ02JM4AWYJZ176Q/attachment/original/01HE892Y8ZS68TQCNPX7J888P3.mp3", CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), Type: gtsmodel.FileTypeUnknown, FileMeta: gtsmodel.FileMeta{}, AccountID: "01FHMQX3GAABWSM0S2VZEC2SWC", Description: "Jolly salsa song, public domain.", Blurhash: "", Processing: 2, File: gtsmodel.File{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/original/01HE88YG74PVAB81PX2XA9F3FG.mp3", ContentType: "audio/mpeg", FileSize: 147819, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), }, Thumbnail: gtsmodel.Thumbnail{ Path: "01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE88YG74PVAB81PX2XA9F3FG.jpg", ContentType: "image/jpeg", FileSize: 0, UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), URL: "http://localhost:8080/fileserver/01FHMQX3GAABWSM0S2VZEC2SWC/attachment/small/01HE88YG74PVAB81PX2XA9F3FG.jpg", }, Avatar: util.Ptr(false), Header: util.Ptr(false), Cached: util.Ptr(false), }, } } // NewTestEmojis returns a map of gts emojis, keyed by the emoji shortcode func NewTestEmojis() map[string]*gtsmodel.Emoji { return map[string]*gtsmodel.Emoji{ "rainbow": { ID: "01F8MH9H8E4VG3KDYJR9EGPXCQ", Shortcode: "rainbow", Domain: "", CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), ImageRemoteURL: "", ImageStaticRemoteURL: "", ImageURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", ImagePath: "01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", ImageStaticURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", ImageStaticPath: "01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", ImageContentType: "image/png", ImageStaticContentType: "image/png", ImageFileSize: 36702, ImageStaticFileSize: 10413, ImageUpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), Disabled: util.Ptr(false), URI: "http://localhost:8080/emoji/01F8MH9H8E4VG3KDYJR9EGPXCQ", VisibleInPicker: util.Ptr(true), CategoryID: "01GGQ8V4993XK67B2JB396YFB7", Cached: util.Ptr(true), }, "yell": { ID: "01GD5KP5CQEE1R3X43Y1EHS2CW", Shortcode: "yell", Domain: "fossbros-anonymous.io", CreatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), UpdatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), ImageRemoteURL: "http://fossbros-anonymous.io/emoji/yell.gif", ImageStaticRemoteURL: "", ImageURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01GD5KP5CQEE1R3X43Y1EHS2CW.png", ImagePath: "01AY6P665V14JJR0AFVRT7311Y/emoji/original/01GD5KP5CQEE1R3X43Y1EHS2CW.png", ImageStaticURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01GD5KP5CQEE1R3X43Y1EHS2CW.png", ImageStaticPath: "01AY6P665V14JJR0AFVRT7311Y/emoji/static/01GD5KP5CQEE1R3X43Y1EHS2CW.png", ImageContentType: "image/png", ImageStaticContentType: "image/png", ImageFileSize: 10889, ImageStaticFileSize: 10808, ImageUpdatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), Disabled: util.Ptr(false), URI: "http://fossbros-anonymous.io/emoji/01GD5KP5CQEE1R3X43Y1EHS2CW", VisibleInPicker: util.Ptr(false), CategoryID: "", Cached: util.Ptr(false), }, } } func NewTestEmojiCategories() map[string]*gtsmodel.EmojiCategory { return map[string]*gtsmodel.EmojiCategory{ "reactions": { ID: "01GGQ8V4993XK67B2JB396YFB7", Name: "reactions", CreatedAt: TimeMustParse("2020-03-18T11:40:55+02:00"), UpdatedAt: TimeMustParse("2020-03-19T12:35:12+02:00"), }, "cute stuff": { ID: "01GGQ989PTT9PMRN4FZ1WWK2B9", Name: "cute stuff", CreatedAt: TimeMustParse("2020-03-20T11:40:55+02:00"), UpdatedAt: TimeMustParse("2020-03-21T12:35:12+02:00"), }, } } func NewTestStatusToEmojis() map[string]*gtsmodel.StatusToEmoji { return map[string]*gtsmodel.StatusToEmoji{ "admin_account_status_1_rainbow": { StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", EmojiID: "01F8MH9H8E4VG3KDYJR9EGPXCQ", }, } } func NewTestInstances() map[string]*gtsmodel.Instance { return map[string]*gtsmodel.Instance{ "localhost:8080": { ID: "01G774F5TSHJ2ZSF7XRC5EMT6K", CreatedAt: TimeMustParse("2020-01-20T13:12:00+02:00"), UpdatedAt: TimeMustParse("2020-01-20T13:12:00+02:00"), Domain: "localhost:8080", URI: "http://localhost:8080", Title: "GoToSocial Testrig Instance", ShortDescription: "This is the GoToSocial testrig. It doesn't federate or anything.
When the testrig is shut down, all data on it will be deleted.
Don't use this in production!
", ShortDescriptionText: "This is the GoToSocial testrig. It doesn't federate or anything.\n\nWhen the testrig is shut down, all data on it will be deleted.\n\nDon't use this in production!", Description: "Here's a fuller description of the GoToSocial testrig instance.
This instance is for testing purposes only. It doesn't federate at all. Go check out https://github.com/superseriousbusiness/gotosocial/tree/main/testrig and https://github.com/superseriousbusiness/gotosocial/blob/main/CONTRIBUTING.md#testing
Users on this instance:
If you need to edit the models for the testrig, you can do so at internal/testmodels.go
.
This is where a list of terms and conditions might go.
For example:
If you want to sign up on this instance, you oughta know that we:
password
wherever possible.Here's a bunch of HTML, read it and weep, weep then!
<section class="about-user">\n <div class="col-header">\n <h2>About</h2>\n </div> \n <div class="fields">\n <h3 class="sr-only">Fields</h3>\n <dl>\n <div class="field">\n <dt>should you follow me?</dt>\n <dd>maybe!</dd>\n </div>\n <div class="field">\n <dt>age</dt>\n <dd>120</dd>\n </div>\n </dl>\n </div>\n <div class="bio">\n <h3 class="sr-only">Bio</h3>\n <p>i post about things that concern me</p>\n </div>\n <div class="sr-only" role="group">\n <h3 class="sr-only">Stats</h3>\n <span>Joined in Jun, 2022.</span>\n <span>8 posts.</span>\n <span>Followed by 1.</span>\n <span>Following 1.</span>\n </div>\n <div class="accountstats" aria-hidden="true">\n <b>Joined</b><time datetime="2022-06-04T13:12:00.000Z">Jun, 2022</time>\n <b>Posts</b><span>8</span>\n <b>Followed by</b><span>1</span>\n <b>Following</b><span>1</span>\n </div>\n</section>\n
There, hope you liked that!
", Text: "Here's a bunch of HTML, read it and weep, weep then!\n\n```html\nhi @admin here's some media for ya
`, AttachmentIDs: []string{"01HE7Y3C432WRSNS10EZM86SA5", "01HE7ZFX9GKA5ZZVD4FACABSS9", "01HE88YG74PVAB81PX2XA9F3FG"}, CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), Local: util.Ptr(false), AccountURI: "http://example.org/users/Some_User", MentionIDs: []string{"01HE7XQNMKTVC8MNPCE1JGK4J3"}, AccountID: "01FHMQX3GAABWSM0S2VZEC2SWC", InReplyToID: "01F8MH75CBF9JFX4ZAD54N0W0R", InReplyToAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", InReplyToURI: "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R", BoostOfID: "", ContentWarning: "some unknown media included", Visibility: gtsmodel.VisibilityPublic, Sensitive: util.Ptr(true), Language: "en", CreatedWithApplicationID: "", Federated: util.Ptr(true), Boostable: util.Ptr(true), Replyable: util.Ptr(true), Likeable: util.Ptr(true), ActivityStreamsType: ap.ObjectNote, }, } } func NewTestPolls() map[string]*gtsmodel.Poll { return map[string]*gtsmodel.Poll{ "local_account_1_status_6_poll": { ID: "01HEN2RKT1YTEZ80SA8HGP105F", Multiple: util.Ptr(false), HideCounts: util.Ptr(true), Options: []string{"good", "bad", "meh"}, Votes: []int{2, 0, 0}, // needs to match stored poll votes Voters: util.Ptr(2), // needs to match stored poll votes StatusID: "01HEN2RZ8BG29Y5Z9VJC73HZW7", Status: nil, ExpiresAt: TimeMustParse("2022-05-21T11:41:10Z"), ClosedAt: time.Time{}, Closing: false, }, "local_account_2_status_8_poll": { ID: "01HEN2QB5NR4NCEHGYC3HN84K6", Multiple: util.Ptr(false), HideCounts: util.Ptr(false), Options: []string{"50:50", "phone a friend", "ask the audience"}, Votes: []int{0, 1, 1}, // needs to match stored poll votes Voters: util.Ptr(2), // needs to match stored poll votes StatusID: "01HEN2PRXT0TF4YDRA64FZZRN7", Status: nil, ExpiresAt: TimeMustParse("2021-08-28T10:40:37+02:00"), ClosedAt: TimeMustParse("2021-08-28T10:40:37+02:00"), Closing: false, }, "remote_account_1_status_2_poll": { ID: "01HEN2R65468ZG657C4ZPHJ4EX", Multiple: util.Ptr(true), HideCounts: util.Ptr(false), Options: []string{"vaseline", "tissues", "financial times"}, Votes: []int{3, 2, 18}, Voters: util.Ptr(6), StatusID: "01HEN2QRFA8H3C6QPN7RD4KSR6", Status: nil, ExpiresAt: TimeMustParse("2021-09-11T12:40:37+02:00"), ClosedAt: TimeMustParse("2021-09-11T12:40:37+02:00"), Closing: false, }, "remote_account_1_status_3_poll": { ID: "01HEWV1GW2D49R919NPEDXPTZ5", Multiple: util.Ptr(true), HideCounts: util.Ptr(false), Options: []string{"vaseline", "tissues", "financial times"}, Votes: []int{0, 0, 0}, Voters: util.Ptr(0), StatusID: "01HEWV37MHV8BAC8ANFGVRRM5D", Status: nil, // nil expiry AND closed date, i.e. no end ExpiresAt: time.Time{}, ClosedAt: time.Time{}, Closing: false, }, } } func NewTestPollVotes() map[string]*gtsmodel.PollVote { return map[string]*gtsmodel.PollVote{ "local_account_1_status_6_poll_vote_local_account_2": { ID: "01HEN2VN4DZ4ENCK6AS4PKM5B3", Choices: []int{0}, AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", Account: nil, PollID: "01HEN2RKT1YTEZ80SA8HGP105F", Poll: nil, CreatedAt: TimeMustParse("2022-05-20T14:41:10Z"), }, "local_account_1_status_6_poll_vote_remote_account_1": { ID: "01HEN2VM975JG8N9KPFQ597KGF", Choices: []int{0}, AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", Account: nil, PollID: "01HEN2RKT1YTEZ80SA8HGP105F", Poll: nil, CreatedAt: TimeMustParse("2022-05-20T15:41:10Z"), }, "local_account_2_status_8_poll_vote_local_account_1": { ID: "01HEN2VK9TX5BTD3B0CSRBWE89", Choices: []int{2}, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Account: nil, PollID: "01HEN2QB5NR4NCEHGYC3HN84K6", Poll: nil, CreatedAt: TimeMustParse("2021-07-29T10:40:37+02:00"), }, "local_account_2_status_8_poll_vote_remote_account_1": { ID: "01HEN2VHW4HAHBM4YH3N55794D", Choices: []int{1}, AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", Account: nil, PollID: "01HEN2QB5NR4NCEHGYC3HN84K6", Poll: nil, CreatedAt: TimeMustParse("2021-08-10T10:40:37+02:00"), }, "remote_account_1_status_2_poll_vote_local_account_1": { ID: "01HEN2VH077W1QY7VKQFPKD6B6", Choices: []int{1, 2}, AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Account: nil, PollID: "01HEN2R65468ZG657C4ZPHJ4EX", Poll: nil, CreatedAt: TimeMustParse("2021-09-11T11:45:37+02:00"), }, "remote_account_1_status_2_poll_vote_local_account_2": { ID: "01HEN2VG6EP3GJA208586H356K", Choices: []int{0, 2}, AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", Account: nil, PollID: "01HEN2R65468ZG657C4ZPHJ4EX", Poll: nil, CreatedAt: TimeMustParse("2021-09-11T11:47:37+02:00"), }, } } // NewTestTags returns a map of gts model tags keyed by their name func NewTestTags() map[string]*gtsmodel.Tag { return map[string]*gtsmodel.Tag{ "welcome": { ID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ", Name: "welcome", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), Useable: util.Ptr(true), Listable: util.Ptr(true), }, "Hashtag": { ID: "01FCT9SGYA71487N8D0S1M638G", Name: "hashtag", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), Useable: util.Ptr(true), Listable: util.Ptr(true), }, } } func NewTestStatusToTags() map[string]*gtsmodel.StatusToTag { return map[string]*gtsmodel.StatusToTag{ "admin_account_status_1_welcome": { StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", TagID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ", }, } } func NewTestThreads() map[string]*gtsmodel.Thread { return map[string]*gtsmodel.Thread{ "admin_account_status_1": { ID: "01HCWDF2Q4HV5QC161C4TGQ0M3", }, "admin_account_status_2": { ID: "01HCWDQ1C7APSEY34B1HFVHVX7", }, "local_account_1_status_1": { ID: "01HCWDKKBWECZJQ93E262N36VN", }, "local_account_1_status_2": { ID: "01HCWDVTW3HQWSX66VJQ91Z1RH", }, "local_account_1_status_3": { ID: "01HCWDY9PDNHDBDBBFTJKJY8XE", }, "local_account_1_status_4": { ID: "01HCWE0H2GKH794Q7GDPANH91Q", }, "local_account_1_status_5": { ID: "01HCWE1ERQSMMVWDD0BE491E2P", }, "local_account_1_status_7": { ID: "01HH9M3FVSF5J7120X9T6PG4GF", }, "local_account_2_status_1": { ID: "01HCWE2Q24FWCZE41AS77SDFRZ", }, "local_account_2_status_2": { ID: "01HCWE3P291Z3NJEJVFPW0K9ZQ", }, "local_account_2_status_3": { ID: "01HCWE4P0EW9HBA5WHW97D5YV0", }, "local_account_2_status_4": { ID: "01HCWE5JXFPFP3P5W2QNHVVV27", }, "local_account_2_status_6": { ID: "01HCWE71MGRRDSHBKXFD5DDSWR", }, "local_account_2_status_7": { ID: "01HCWE7ZNC2SS4P05WA5QYED23", }, } } func NewTestThreadToStatus() []*gtsmodel.ThreadToStatus { return []*gtsmodel.ThreadToStatus{ { ThreadID: "01HCWDF2Q4HV5QC161C4TGQ0M3", StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", }, { ThreadID: "01HCWDQ1C7APSEY34B1HFVHVX7", StatusID: "01F8MHAAY43M6RJ473VQFCVH37", }, { ThreadID: "01HCWDKKBWECZJQ93E262N36VN", StatusID: "01FF25D5Q0DH7CHD57CTRS6WK0", }, { ThreadID: "01HCWDKKBWECZJQ93E262N36VN", StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", }, { ThreadID: "01HCWDVTW3HQWSX66VJQ91Z1RH", StatusID: "01F8MHAYFKS4KMXF8K5Y1C0KRN", }, { ThreadID: "01HCWDY9PDNHDBDBBFTJKJY8XE", StatusID: "01F8MHBBN8120SYH7D5S050MGK", }, { ThreadID: "01HCWE0H2GKH794Q7GDPANH91Q", StatusID: "01F8MH82FYRXD2RC6108DAJ5HB", }, { ThreadID: "01HCWE1ERQSMMVWDD0BE491E2P", StatusID: "01FCTA44PW9H1TB328S9AQXKDS", }, { ThreadID: "01HCWE2Q24FWCZE41AS77SDFRZ", StatusID: "01F8MHBQCBTDKN6X5VHGMMN4MA", }, { ThreadID: "01HCWE3P291Z3NJEJVFPW0K9ZQ", StatusID: "01F8MHC0H0A7XHTVH5F596ZKBM", }, { ThreadID: "01HCWE4P0EW9HBA5WHW97D5YV0", StatusID: "01F8MHC8VWDRBQR0N1BATDDEM5", }, { ThreadID: "01HCWDKKBWECZJQ93E262N36VN", StatusID: "01FCQSQ667XHJ9AV9T27SJJSX5", }, { ThreadID: "01HCWE71MGRRDSHBKXFD5DDSWR", StatusID: "01FN3VJGFH10KR7S2PB0GFJZYG", }, { ThreadID: "01HCWE7ZNC2SS4P05WA5QYED23", StatusID: "01G20ZM733MGN8J344T4ZDDFY1", }, } } // NewTestMentions returns a map of gts model mentions keyed by their name. func NewTestMentions() map[string]*gtsmodel.Mention { return map[string]*gtsmodel.Mention{ "zork_mention_foss_satan": { ID: "01FCTA2Y6FGHXQA4ZE6N5NMNEX", StatusID: "01FCTA44PW9H1TB328S9AQXKDS", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), OriginAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", OriginAccountURI: "http://localhost:8080/users/the_mighty_zork", TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", NameString: "@foss_satan@fossbros-anonymous.io", TargetAccountURI: "http://fossbros-anonymous.io/users/foss_satan", TargetAccountURL: "http://fossbros-anonymous.io/@foss_satan", }, "local_user_2_mention_zork": { ID: "01FDF2HM2NF6FSRZCDEDV451CN", StatusID: "01FCQSQ667XHJ9AV9T27SJJSX5", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", OriginAccountURI: "http://localhost:8080/users/1happyturtle", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", NameString: "@the_mighty_zork", TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", TargetAccountURL: "http://localhost:8080/@the_mighty_zork", }, "local_user_2_mention_zork_direct_message": { ID: "01FN3VKDEF4CN2W9TKX339BEHB", StatusID: "01FN3VJGFH10KR7S2PB0GFJZYG", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", OriginAccountURI: "http://localhost:8080/users/1happyturtle", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", NameString: "@the_mighty_zork", TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", TargetAccountURL: "http://localhost:8080/@the_mighty_zork", }, "admin_account_mention_zork": { ID: "01FF26A6BGEKCZFWNEHXB2ZZ6M", StatusID: "01FF25D5Q0DH7CHD57CTRS6WK0", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", OriginAccountURI: "http://localhost:8080/users/admin", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", NameString: "@the_mighty_zork", TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", TargetAccountURL: "http://localhost:8080/@the_mighty_zork", }, "remote_account_2_mention_admin": { ID: "01HE7XQNMKTVC8MNPCE1JGK4J3", StatusID: "01HE7XJ1CG84TBKH5V9XKBVGF5", CreatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), UpdatedAt: TimeMustParse("2023-11-02T12:44:25+02:00"), OriginAccountID: "01FHMQX3GAABWSM0S2VZEC2SWC", OriginAccountURI: "http://example.org/users/Some_User", TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", NameString: "@admin@localhost:8080", TargetAccountURI: "http://localhost:8080/users/admin", TargetAccountURL: "http://localhost:8080/@admin", }, } } // NewTestFaves returns a map of gts model faves, keyed in the format [faving_account]_[target_status] func NewTestFaves() map[string]*gtsmodel.StatusFave { return map[string]*gtsmodel.StatusFave{ "local_account_1_admin_account_status_1": { ID: "01F8MHD2QCZSZ6WQS2ATVPEYJ9", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", // admin account status 1 URI: "http://localhost:8080/users/the_mighty_zork/liked/01F8MHD2QCZSZ6WQS2ATVPEYJ9", }, "local_account_1_admin_account_status_3": { ID: "01GM435XERVPXXRK6NBAHK5HCZ", CreatedAt: TimeMustParse("2022-12-12T20:17:56+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account StatusID: "01F8MHAAY43M6RJ473VQFCVH37", // admin account status 1 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM435XERVPXXRK6NBAHK5HCZ", }, "local_account_1_local_account_2_status_1": { ID: "01GM43AKBMN4YNXQ1HZHVC1SGB", CreatedAt: TimeMustParse("2022-12-12T20:19:49+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", // admin account StatusID: "01F8MHBQCBTDKN6X5VHGMMN4MA", // admin account status 1 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM43AKBMN4YNXQ1HZHVC1SGB", }, "local_account_1_local_account_2_status_4": { ID: "01GM43CC47DRPNZZ7BD04BS1YZ", CreatedAt: TimeMustParse("2022-12-12T20:20:47+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", // admin account StatusID: "01F8MHCP5P2NWYQ416SBA0XSEV", // admin account status 1 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM43CC47DRPNZZ7BD04BS1YZ", }, "admin_account_local_account_1_status_1": { ID: "01F8Q0486ANTDWKG02A7DS1Q24", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", // local account status 1 URI: "http://localhost:8080/users/admin/liked/01F8Q0486ANTDWKG02A7DS1Q24", }, } } // NewTestAccountNotes returns some account notes for use in testing. func NewTestAccountNotes() map[string]*gtsmodel.AccountNote { return map[string]*gtsmodel.AccountNote{ "local_account_2_note_on_1": { ID: "01H53TM628GNC4ZDNRGQGPK8S0", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Comment: "extremely average poster", }, } } // NewTestNotifications returns some notifications for use in testing. func NewTestNotifications() map[string]*gtsmodel.Notification { return map[string]*gtsmodel.Notification{ "local_account_1_like": { ID: "01F8Q0ANPTWW10DAKTX7BRPBJP", NotificationType: gtsmodel.NotificationFave, CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", Read: util.Ptr(false), }, "local_account_2_like": { ID: "01GTS6PRPXJYZBPFFQ56PP0XR8", NotificationType: gtsmodel.NotificationFave, CreatedAt: TimeMustParse("2022-01-13T12:45:01+02:00"), TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", Read: util.Ptr(false), }, } } // NewTestFollows returns some follows for use in testing. func NewTestFollows() map[string]*gtsmodel.Follow { return map[string]*gtsmodel.Follow{ "local_account_1_admin_account": { ID: "01F8PY8RHWRQZV038T4E8T9YK8", CreatedAt: TimeMustParse("2022-05-14T16:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T16:21:09+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", ShowReblogs: util.Ptr(true), URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PY8RHWRQZV038T4E8T9YK8", Notify: util.Ptr(false), }, "local_account_1_local_account_2": { ID: "01F8PYDCE8XE23GRE5DPZJDZDP", CreatedAt: TimeMustParse("2022-05-14T15:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T15:21:09+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", ShowReblogs: util.Ptr(true), URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PYDCE8XE23GRE5DPZJDZDP", Notify: util.Ptr(false), }, "local_account_2_local_account_1": { ID: "01G1TK1RS4K3E0MSFTXBFWAH9Q", CreatedAt: TimeMustParse("2022-05-14T14:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T14:21:09+02:00"), AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", ShowReblogs: util.Ptr(true), URI: "http://localhost:8080/users/1happyturtle/follow/01F8PYDCE8XE23GRE5DPZJDZDP", Notify: util.Ptr(false), }, "admin_account_local_account_1": { ID: "01G1TK3PQKFW1BQZ9WVYRTFECK", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", ShowReblogs: util.Ptr(true), URI: "http://localhost:8080/users/admin/follow/01G1TK3PQKFW1BQZ9WVYRTFECK", Notify: util.Ptr(false), }, } } func NewTestLists() map[string]*gtsmodel.List { return map[string]*gtsmodel.List{ "local_account_1_list_1": { ID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), Title: "Cool Ass Posters From This Instance", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", RepliesPolicy: gtsmodel.RepliesPolicyFollowed, }, } } func NewTestListEntries() map[string]*gtsmodel.ListEntry { return map[string]*gtsmodel.ListEntry{ "local_account_1_list_1_entry_1": { ID: "01H0G89MWVQE0M58VD2HQYMQWH", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), ListID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", FollowID: "01F8PYDCE8XE23GRE5DPZJDZDP", }, "local_account_1_list_1_entry_2": { ID: "01H0G8FFM1AGQDRNGBGGX8CYJQ", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), ListID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", FollowID: "01F8PY8RHWRQZV038T4E8T9YK8", }, } } func NewTestMarkers() map[string]*gtsmodel.Marker { return map[string]*gtsmodel.Marker{ "local_account_1_home_marker": { AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Name: gtsmodel.MarkerNameHome, UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), Version: 0, LastReadID: "01F8MH82FYRXD2RC6108DAJ5HB", }, "local_account_1_notification_marker": { AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Name: gtsmodel.MarkerNameNotifications, UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), Version: 4, LastReadID: "01F8Q0ANPTWW10DAKTX7BRPBJP", }, } } func NewTestBlocks() map[string]*gtsmodel.Block { return map[string]*gtsmodel.Block{ "local_account_2_block_remote_account_1": { ID: "01FEXXET6XXMF7G2V3ASZP3YQW", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), URI: "http://localhost:8080/users/1happyturtle/blocks/01FEXXET6XXMF7G2V3ASZP3YQW", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", }, } } func NewTestReports() map[string]*gtsmodel.Report { return map[string]*gtsmodel.Report{ "local_account_2_report_remote_account_1": { ID: "01GP3AWY4CRDVRNZKW0TEAMB5R", CreatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), UpdatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), URI: "http://localhost:8080/reports/01GP3AWY4CRDVRNZKW0TEAMB5R", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", Comment: "dark souls sucks, please yeet this nerd", StatusIDs: []string{"01FVW7JHQFSFK166WWKR8CBA6M"}, Forwarded: util.Ptr(true), RuleIDs: []string{"01GP3AWY4CRDVRNZKW0TEAMB51", "01GP3DFY9XQ1TJMZT5BGAZPXX3"}, }, "remote_account_1_report_local_account_2": { ID: "01GP3DFY9XQ1TJMZT5BGAZPXX7", CreatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), UpdatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), URI: "http://fossbros-anonymous.io/87fb1478-ac46-406a-8463-96ce05645219", AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", Comment: "this is a turtle, not a person, therefore should not be a poster", StatusIDs: []string{}, RuleIDs: []string{}, Forwarded: util.Ptr(true), ActionTaken: "user was warned not to be a turtle anymore", ActionTakenAt: TimeMustParse("2022-05-15T17:01:56+02:00"), ActionTakenByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", }, } } func NewTestRules() map[string]*gtsmodel.Rule { return map[string]*gtsmodel.Rule{ "rule1": { ID: "01GP3AWY4CRDVRNZKW0TEAMB51", CreatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), UpdatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), Text: "Be gay", Deleted: util.Ptr(false), Order: util.Ptr(uint(0)), }, "deleted_rule": { ID: "01GP3DFY9XQ1TJMZT5BGAZPXX2", CreatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), UpdatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), Text: "Deleted", Deleted: util.Ptr(true), Order: util.Ptr(uint(1)), }, "rule2": { ID: "01GP3DFY9XQ1TJMZT5BGAZPXX3", CreatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), UpdatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), Text: "Do crime", Deleted: util.Ptr(false), Order: util.Ptr(uint(2)), }, } } // ActivityWithSignature wraps a pub.Activity along with its signature headers, for testing. type ActivityWithSignature struct { Activity pub.Activity SignatureHeader string DigestHeader string DateHeader string } // NewTestActivities returns a bunch of pub.Activity types for use in testing the federation protocols. // A struct of accounts needs to be passed in because the activities will also be bundled along with // their requesting signatures. func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]ActivityWithSignature { dmForZork := NewAPNote( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6"), URLMustParse("http://fossbros-anonymous.io/@foss_satan/5424b153-4553-4f30-9358-7b92f7cd42f6"), TimeMustParse("2022-07-13T12:13:12+02:00"), "@the_mighty_zork@localhost:8080 hey zork here's a new private note for you", "new note for zork", URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), []*url.URL{URLMustParse("http://localhost:8080/users/the_mighty_zork")}, nil, true, []vocab.ActivityStreamsMention{newAPMention( URLMustParse("http://localhost:8080/users/the_mighty_zork"), "@the_mighty_zork@localhost:8080", )}, []vocab.TootHashtag{}, nil, ) createDmForZork := WrapAPNoteInCreate( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6/activity"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), TimeMustParse("2022-07-13T12:13:12+02:00"), dmForZork) createDmForZorkSig, createDmForZorkDigest, creatDmForZorkDate := GetSignatureForActivity(createDmForZork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) replyToTurtle := NewAPNote( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), URLMustParse("http://fossbros-anonymous.io/@foss_satan/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), TimeMustParse("2022-07-13T12:13:12+02:00"), "@1happyturtle@localhost:8080 u suck lol", "", URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), []*url.URL{URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")}, []*url.URL{URLMustParse("http://localhost:8080/users/1happyturtle")}, false, []vocab.ActivityStreamsMention{newAPMention( URLMustParse("http://localhost:8080/users/1happyturtle"), "@1happyturtle@localhost:8080", )}, []vocab.TootHashtag{}, nil, ) createReplyToTurtle := WrapAPNoteInCreate( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), TimeMustParse("2022-07-13T12:13:12+02:00"), replyToTurtle) createReplyToTurtleForZorkSig, createReplyToTurtleForZorkDigest, createReplyToTurtleForZorkDate := GetSignatureForActivity(createReplyToTurtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) createReplyToTurtleForTurtleSig, createReplyToTurtleForTurtleDigest, createReplyToTurtleForTurtleDate := GetSignatureForActivity(createReplyToTurtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_2"].InboxURI)) forwardedMessage := NewAPNote( URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"), URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"), TimeMustParse("2022-07-13T12:13:12+02:00"), "this is a public status, please forward it!", "", URLMustParse("http://example.org/users/Some_User"), []*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, nil, false, []vocab.ActivityStreamsMention{}, []vocab.TootHashtag{}, []vocab.ActivityStreamsImage{ newAPImage( URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"), "image/jpeg", "trent reznor looking handsome as balls", "LEDara58O=t5EMSOENEN9]}?aK%0"), }, ) createForwardedMessage := WrapAPNoteInCreate( URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/activity"), URLMustParse("http://example.org/users/Some_User"), TimeMustParse("2022-07-13T12:13:12+02:00"), forwardedMessage) createForwardedMessageSig, createForwardedMessageDigest, createForwardedMessageDate := GetSignatureForActivity(createForwardedMessage, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) announceForwarded1Zork := newAPAnnounce( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/first_announce"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), TimeMustParse("2022-07-13T12:13:12+02:00"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), forwardedMessage, ) announceForwarded1ZorkSig, announceForwarded1ZorkDigest, announceForwarded1ZorkDate := GetSignatureForActivity(announceForwarded1Zork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) announceForwarded1Turtle := newAPAnnounce( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/first_announce"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), TimeMustParse("2022-07-13T12:13:12+02:00"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), forwardedMessage, ) announceForwarded1TurtleSig, announceForwarded1TurtleDigest, announceForwarded1TurtleDate := GetSignatureForActivity(announceForwarded1Turtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_2"].InboxURI)) announceForwarded2Zork := newAPAnnounce( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/second_announce"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), TimeMustParse("2022-07-13T12:13:12+02:00"), URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), forwardedMessage, ) announceForwarded2ZorkSig, announceForwarded2ZorkDigest, announceForwarded2ZorkDate := GetSignatureForActivity(announceForwarded2Zork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) deleteForRemoteAccount3 := newAPDelete( URLMustParse("https://somewhere.mysterious/users/rest_in_piss"), URLMustParse("https://somewhere.mysterious/users/rest_in_piss"), TimeMustParse("2022-07-13T12:13:12+02:00"), URLMustParse(accounts["local_account_1"].URI), ) // it doesn't really matter what key we use to sign this, since we're not going to be able to verify if anyway keyToSignDelete := accounts["remote_account_1"].PrivateKey deleteForRemoteAccount3Sig, deleteForRemoteAccount3Digest, deleteForRemoteAccount3Date := GetSignatureForActivity(deleteForRemoteAccount3, "https://somewhere.mysterious/users/rest_in_piss#main-key", keyToSignDelete, URLMustParse(accounts["local_account_1"].InboxURI)) return map[string]ActivityWithSignature{ "dm_for_zork": { Activity: createDmForZork, SignatureHeader: createDmForZorkSig, DigestHeader: createDmForZorkDigest, DateHeader: creatDmForZorkDate, }, "reply_to_turtle_for_zork": { Activity: createReplyToTurtle, SignatureHeader: createReplyToTurtleForZorkSig, DigestHeader: createReplyToTurtleForZorkDigest, DateHeader: createReplyToTurtleForZorkDate, }, "reply_to_turtle_for_turtle": { Activity: createReplyToTurtle, SignatureHeader: createReplyToTurtleForTurtleSig, DigestHeader: createReplyToTurtleForTurtleDigest, DateHeader: createReplyToTurtleForTurtleDate, }, "forwarded_message": { Activity: createForwardedMessage, SignatureHeader: createForwardedMessageSig, DigestHeader: createForwardedMessageDigest, DateHeader: createForwardedMessageDate, }, "announce_forwarded_1_zork": { Activity: announceForwarded1Zork, SignatureHeader: announceForwarded1ZorkSig, DigestHeader: announceForwarded1ZorkDigest, DateHeader: announceForwarded1ZorkDate, }, "announce_forwarded_1_turtle": { Activity: announceForwarded1Turtle, SignatureHeader: announceForwarded1TurtleSig, DigestHeader: announceForwarded1TurtleDigest, DateHeader: announceForwarded1TurtleDate, }, "announce_forwarded_2_zork": { Activity: announceForwarded2Zork, SignatureHeader: announceForwarded2ZorkSig, DigestHeader: announceForwarded2ZorkDigest, DateHeader: announceForwarded2ZorkDate, }, "delete_https://somewhere.mysterious/users/rest_in_piss#main-key": { Activity: deleteForRemoteAccount3, SignatureHeader: deleteForRemoteAccount3Sig, DigestHeader: deleteForRemoteAccount3Digest, DateHeader: deleteForRemoteAccount3Date, }, } } // NewTestFediPeople returns a bunch of activity pub Person representations for testing converters and so on. func NewTestFediPeople() map[string]vocab.ActivityStreamsPerson { newPerson1Priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } newPerson1Pub := &newPerson1Priv.PublicKey turnipLover6969Priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } turnipLover6969Pub := &turnipLover6969Priv.PublicKey someUserPriv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } someUserPub := &someUserPriv.PublicKey return map[string]vocab.ActivityStreamsPerson{ "https://unknown-instance.com/users/brand_new_person": newAPPerson( URLMustParse("https://unknown-instance.com/users/brand_new_person"), URLMustParse("https://unknown-instance.com/users/brand_new_person/following"), URLMustParse("https://unknown-instance.com/users/brand_new_person/followers"), URLMustParse("https://unknown-instance.com/users/brand_new_person/inbox"), nil, URLMustParse("https://unknown-instance.com/users/brand_new_person/outbox"), URLMustParse("https://unknown-instance.com/users/brand_new_person/collections/featured"), nil, nil, "brand_new_person", "Geoff Brando New Personson", "hey I'm a new person, your instance hasn't seen me yet uwu", URLMustParse("https://unknown-instance.com/@brand_new_person"), true, URLMustParse("https://unknown-instance.com/users/brand_new_person#main-key"), newPerson1Pub, nil, "image/jpeg", nil, "image/png", false, ), "https://turnip.farm/users/turniplover6969": newAPPerson( URLMustParse("https://turnip.farm/users/turniplover6969"), URLMustParse("https://turnip.farm/users/turniplover6969/following"), URLMustParse("https://turnip.farm/users/turniplover6969/followers"), URLMustParse("https://turnip.farm/users/turniplover6969/inbox"), URLMustParse("https://turnip.farm/sharedInbox"), URLMustParse("https://turnip.farm/users/turniplover6969/outbox"), URLMustParse("https://turnip.farm/users/turniplover6969/collections/featured"), nil, nil, "turniplover6969", "Turnip Lover 6969", "I just think they're neat", URLMustParse("https://turnip.farm/@turniplover6969"), true, URLMustParse("https://turnip.farm/users/turniplover6969#main-key"), turnipLover6969Pub, nil, "image/jpeg", nil, "image/png", false, ), "http://example.org/users/Some_User": newAPPerson( URLMustParse("http://example.org/users/Some_User"), URLMustParse("http://example.org/users/Some_User/following"), URLMustParse("http://example.org/users/Some_User/followers"), URLMustParse("http://example.org/users/Some_User/inbox"), URLMustParse("http://example.org/sharedInbox"), URLMustParse("http://example.org/users/Some_User/outbox"), URLMustParse("http://example.org/users/Some_User/collections/featured"), nil, nil, "Some_User", "just some user, don't mind me", "Peepee poo poo", URLMustParse("http://example.org/@Some_User"), true, URLMustParse("http://example.org/users/Some_User#main-key"), someUserPub, nil, "image/jpeg", nil, "image/png", false, ), } } func NewTestFediGroups() map[string]vocab.ActivityStreamsGroup { newGroup1Priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } newGroup1Pub := &newGroup1Priv.PublicKey return map[string]vocab.ActivityStreamsGroup{ "https://unknown-instance.com/groups/some_group": newAPGroup( URLMustParse("https://unknown-instance.com/groups/some_group"), URLMustParse("https://unknown-instance.com/groups/some_group/following"), URLMustParse("https://unknown-instance.com/groups/some_group/followers"), URLMustParse("https://unknown-instance.com/groups/some_group/inbox"), URLMustParse("https://unknown-instance.com/groups/some_group/outbox"), URLMustParse("https://unknown-instance.com/groups/some_group/collections/featured"), "some_group", "This is a group about... something?", "", URLMustParse("https://unknown-instance.com/@some_group"), true, URLMustParse("https://unknown-instance.com/groups/some_group#main-key"), newGroup1Pub, nil, "image/jpeg", nil, "image/png", false, ), } } 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, ), } } func NewTestFediEmojis() map[string]vocab.TootEmoji { return map[string]vocab.TootEmoji{ "http://fossbros-anonymous.io/emoji/01GD5HCC2YECT012TK8PAGX4D1": newAPEmoji( URLMustParse("http://fossbros-anonymous.io/emoji/01GD5HCC2YECT012TK8PAGX4D1"), "kip_van_den_bos", TimeMustParse("2022-09-13T12:13:12+02:00"), newAPImage( URLMustParse("http://fossbros-anonymous.io/emoji/kip.gif"), "image/gif", "", "", ), ), } } // RemoteAttachmentFile mimics a remote (federated) attachment type RemoteAttachmentFile struct { Data []byte ContentType string } func NewTestFediAttachments(relativePath string) map[string]RemoteAttachmentFile { beeBytes, err := os.ReadFile(fmt.Sprintf("%s/beeplushie.jpg", relativePath)) if err != nil { panic(err) } thoughtsOfDogBytes, err := os.ReadFile(fmt.Sprintf("%s/thoughtsofdog-original.jpg", relativePath)) if err != nil { panic(err) } massiveFuckingTurnipBytes, err := os.ReadFile(fmt.Sprintf("%s/giant-turnip-world-record.jpg", relativePath)) if err != nil { panic(err) } peglinBytes, err := os.ReadFile(fmt.Sprintf("%s/peglin.gif", relativePath)) if err != nil { panic(err) } kipBytes, err := os.ReadFile(fmt.Sprintf("%s/kip-original.gif", relativePath)) if err != nil { panic(err) } yellBytes, err := os.ReadFile(fmt.Sprintf("%s/yell-original.png", relativePath)) if err != nil { panic(err) } return map[string]RemoteAttachmentFile{ "https://s3-us-west-2.amazonaws.com/plushcity/media_attachments/files/106/867/380/219/163/828/original/88e8758c5f011439.jpg": { Data: beeBytes, ContentType: "image/jpeg", }, "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg": { Data: thoughtsOfDogBytes, ContentType: "image/jpeg", }, "https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg": { Data: massiveFuckingTurnipBytes, ContentType: "image/jpeg", }, "http://example.org/media/emojis/1781772.gif": { Data: peglinBytes, ContentType: "image/gif", }, "http://fossbros-anonymous.io/emoji/kip.gif": { Data: kipBytes, ContentType: "image/gif", }, "http://fossbros-anonymous.io/emoji/yell.gif": { Data: yellBytes, ContentType: "image/png", }, } } func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { return map[string]vocab.ActivityStreamsNote{ "http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1": NewAPNote( URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"), URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"), TimeMustParse("2022-07-13T12:13:12+02:00"), "this is a public status, please forward it!", "", URLMustParse("http://example.org/users/Some_User"), []*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, nil, false, []vocab.ActivityStreamsMention{}, []vocab.TootHashtag{}, []vocab.ActivityStreamsImage{ newAPImage( URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"), "image/jpeg", "trent reznor looking handsome as balls", "LEDara58O=t5EMSOENEN9]}?aK%0"), }, ), "https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839": NewAPNote( URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839"), URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839"), TimeMustParse("2022-07-13T12:13:12+02:00"), "Hello world!", "", URLMustParse("https://unknown-instance.com/users/brand_new_person"), []*url.URL{ URLMustParse(pub.PublicActivityPubIRI), }, []*url.URL{}, false, nil, []vocab.TootHashtag{}, nil, ), "https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV": NewAPNote( URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV"), URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV"), TimeMustParse("2022-07-13T12:13:12+02:00"), "Hey @the_mighty_zork@localhost:8080 how's it going?", "", URLMustParse("https://unknown-instance.com/users/brand_new_person"), []*url.URL{ URLMustParse(pub.PublicActivityPubIRI), }, []*url.URL{}, false, []vocab.ActivityStreamsMention{ newAPMention( URLMustParse("http://localhost:8080/users/the_mighty_zork"), "@the_mighty_zork@localhost:8080", ), }, []vocab.TootHashtag{}, nil, ), "https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7": NewAPNote( URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"), URLMustParse("https://unknown-instance.com/users/@brand_new_person/01H641QSRS3TCXSVC10X4GPKW7"), TimeMustParse("2023-04-12T12:13:12+02:00"), "Babe are you okay, you've hardly touched your #piss
", "", URLMustParse("https://unknown-instance.com/users/brand_new_person"), []*url.URL{ URLMustParse(pub.PublicActivityPubIRI), }, []*url.URL{}, false, []vocab.ActivityStreamsMention{}, []vocab.TootHashtag{ newAPHashtag( URLMustParse("https://unknown-instance.com/tags/piss"), "#piss", ), }, nil, ), "https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042": NewAPNote( URLMustParse("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042"), URLMustParse("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042"), TimeMustParse("2022-07-13T12:13:12+02:00"), "", "", URLMustParse("https://turnip.farm/users/turniplover6969"), []*url.URL{ URLMustParse(pub.PublicActivityPubIRI), }, []*url.URL{}, false, nil, []vocab.TootHashtag{}, []vocab.ActivityStreamsImage{ newAPImage( URLMustParse("https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg"), "image/jpeg", "", "", ), }, ), "http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552": NewAPNote( URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552"), URLMustParse("http://fossbros-anonymous.io/@foss_satan/106221634728637552"), TimeMustParse("2022-07-13T12:13:12+02:00"), `@the_mighty_zork nice there it is:
https://social.pixie.town/users/f0x/statuses/106221628567855262/activity
`, "", URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), []*url.URL{ URLMustParse(pub.PublicActivityPubIRI), }, []*url.URL{}, false, []vocab.ActivityStreamsMention{ newAPMention( URLMustParse("http://localhost:8080/users/the_mighty_zork"), "@the_mighty_zork@localhost:8080", ), }, []vocab.TootHashtag{}, nil, ), } } // NewTestBookmarks returns a map of gts model bookmarks, keyed in the format [bookmarking_account]_[target_status] func NewTestBookmarks() map[string]*gtsmodel.StatusBookmark { return map[string]*gtsmodel.StatusBookmark{ "local_account_1_admin_account_status_1": { ID: "01F8MHD2QCZSZ6WQS2ATVPEYJ9", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", // admin account status 1 }, "admin_account_local_account_1_status_1": { ID: "01F8Q0486ANTDWKG02A7DS1Q24", CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", // local account status 1 }, } } // NewTestDereferenceRequests returns a map of incoming dereference requests, with their signatures. func NewTestDereferenceRequests(accounts map[string]*gtsmodel.Account) map[string]ActivityWithSignature { var sig, digest, date string var target *url.URL statuses := NewTestStatuses() emojis := NewTestEmojis() target = URLMustParse(accounts["local_account_1"].URI) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceZork := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(accounts["local_account_1"].PublicKeyURI) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceZorkPublicKey := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(statuses["local_account_1_status_1"].URI) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceLocalAccount1Status1 := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(strings.ToLower(statuses["local_account_1_status_1"].URI)) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceLocalAccount1Status1Lowercase := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies?only_other_accounts=false") sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceLocalAccount1Status1Replies := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies?only_other_accounts=false&page=true") sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceLocalAccount1Status1RepliesNext := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies?min_id=01FF25D5Q0DH7CHD57CTRS6WK0&only_other_accounts=false") sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceLocalAccount1Status1RepliesLast := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(accounts["local_account_1"].OutboxURI) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceZorkOutbox := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(accounts["local_account_1"].OutboxURI + "?page=true") sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceZorkOutboxFirst := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(accounts["local_account_1"].OutboxURI + "?page=true&max_id=01F8MHAMCHF6Y650WCRSCP4WMY") sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceZorkOutboxNext := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } target = URLMustParse(emojis["rainbow"].URI) sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) fossSatanDereferenceEmoji := ActivityWithSignature{ SignatureHeader: sig, DigestHeader: digest, DateHeader: date, } return map[string]ActivityWithSignature{ "foss_satan_dereference_zork": fossSatanDereferenceZork, "foss_satan_dereference_zork_public_key": fossSatanDereferenceZorkPublicKey, "foss_satan_dereference_local_account_1_status_1": fossSatanDereferenceLocalAccount1Status1, "foss_satan_dereference_local_account_1_status_1_lowercase": fossSatanDereferenceLocalAccount1Status1Lowercase, "foss_satan_dereference_local_account_1_status_1_replies": fossSatanDereferenceLocalAccount1Status1Replies, "foss_satan_dereference_local_account_1_status_1_replies_next": fossSatanDereferenceLocalAccount1Status1RepliesNext, "foss_satan_dereference_local_account_1_status_1_replies_last": fossSatanDereferenceLocalAccount1Status1RepliesLast, "foss_satan_dereference_zork_outbox": fossSatanDereferenceZorkOutbox, "foss_satan_dereference_zork_outbox_first": fossSatanDereferenceZorkOutboxFirst, "foss_satan_dereference_zork_outbox_next": fossSatanDereferenceZorkOutboxNext, "foss_satan_dereference_emoji": fossSatanDereferenceEmoji, } } func NewTestFilters() map[string]*gtsmodel.Filter { return map[string]*gtsmodel.Filter{ "local_account_1_filter_1": { ID: "01HN26VM6KZTW1ANNRVSBMA461", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Title: "fnord", Action: gtsmodel.FilterActionWarn, ContextHome: util.Ptr(true), ContextPublic: util.Ptr(true), }, "local_account_1_filter_2": { ID: "01HN277FSPQAWXZXK92QPPYF79", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", Title: "metasyntactic variables", Action: gtsmodel.FilterActionWarn, ContextHome: util.Ptr(true), ContextPublic: util.Ptr(true), }, "local_account_2_filter_1": { ID: "01HNGFYJBED9FS0VWRVMY4TKXH", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1VYJAE00TVVGMM5JNJ8X", Title: "gamer words", Action: gtsmodel.FilterActionWarn, ContextHome: util.Ptr(true), ContextPublic: util.Ptr(true), }, } } func NewTestFilterKeywords() map[string]*gtsmodel.FilterKeyword { return map[string]*gtsmodel.FilterKeyword{ "local_account_1_filter_1_keyword_1": { ID: "01HN272TAVWAXX72ZX4M8JZ0PS", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", FilterID: "01HN26VM6KZTW1ANNRVSBMA461", Keyword: "fnord", WholeWord: util.Ptr(true), }, "local_account_1_filter_2_keyword_1": { ID: "01HN277Y11ENG4EC1ERMAC9FH4", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", FilterID: "01HN277FSPQAWXZXK92QPPYF79", Keyword: "foo", WholeWord: util.Ptr(true), }, "local_account_1_filter_2_keyword_2": { ID: "01HN278494N88BA2FY4DZ5JTNS", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", FilterID: "01HN277FSPQAWXZXK92QPPYF79", Keyword: "bar", WholeWord: util.Ptr(true), }, "local_account_2_filter_1_keyword_1": { ID: "01HNGG51HV2JT67XQ5MQ7RA1WE", CreatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), UpdatedAt: TimeMustParse("2024-01-25T12:20:03+02:00"), AccountID: "01F8MH1VYJAE00TVVGMM5JNJ8X", FilterID: "01HNGFYJBED9FS0VWRVMY4TKXH", Keyword: "Virtual Boy", WholeWord: util.Ptr(true), }, } } func NewTestFilterStatuses() map[string]*gtsmodel.FilterStatus { // FUTURE: (filters v2) test filter statuses return map[string]*gtsmodel.FilterStatus{} } // GetSignatureForActivity prepares a mock HTTP request as if it were going to deliver activity to destination signed for privkey and pubKeyID, signs the request and returns the header values. func GetSignatureForActivity(activity pub.Activity, pubKeyID string, privkey *rsa.PrivateKey, destination *url.URL) (signatureHeader string, digestHeader string, dateHeader string) { // convert the activity into json bytes m, err := activity.Serialize() if err != nil { panic(err) } b, err := json.Marshal(m) if err != nil { panic(err) } // Prepare HTTP request signer sig, err := transport.NewPOSTSigner(120) if err != nil { panic(err) } // Prepare a mock request ready for signing r, err := http.NewRequest("POST", destination.String(), bytes.NewReader(b)) if err != nil { panic(err) } r.Header.Set("Host", destination.Host) r.Header.Set("Date", time.Now().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") // Sign this new HTTP request if err := sig.SignRequest(privkey, pubKeyID, r, b); err != nil { panic(err) } // Load signed data from request signatureHeader = r.Header.Get("Signature") digestHeader = r.Header.Get("Digest") dateHeader = r.Header.Get("Date") // headers should now be populated return } // GetSignatureForDereference prepares a mock HTTP request as if it were going to dereference destination signed for privkey and pubKeyID, signs the request and returns the header values. func GetSignatureForDereference(pubKeyID string, privkey *rsa.PrivateKey, destination *url.URL) (signatureHeader string, digestHeader string, dateHeader string) { // Prepare HTTP request signer sig, err := transport.NewGETSigner(120) if err != nil { panic(err) } // Prepare a mock request ready for signing r, err := http.NewRequest("GET", destination.String(), nil) if err != nil { panic(err) } r.Header.Set("Host", destination.Host) r.Header.Set("Date", time.Now().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") // Sign this new HTTP request if err := sig.SignRequest(privkey, pubKeyID, r, nil); err != nil { panic(err) } // Load signed data from request signatureHeader = r.Header.Get("Signature") digestHeader = r.Header.Get("Digest") dateHeader = r.Header.Get("Date") // headers should now be populated return } func newAPPerson( profileIDURI *url.URL, followingURI *url.URL, followersURI *url.URL, inboxURI *url.URL, sharedInboxIRI *url.URL, outboxURI *url.URL, featuredURI *url.URL, movedToURI *url.URL, alsoKnownAsURIs []*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.ActivityStreamsPerson { person := streams.NewActivityStreamsPerson() // id should be the activitypub URI of this user // something like https://example.org/users/example_user idProp := streams.NewJSONLDIdProperty() idProp.SetIRI(profileIDURI) person.SetJSONLDId(idProp) // following // The URI for retrieving a list of accounts this user is following followingProp := streams.NewActivityStreamsFollowingProperty() followingProp.SetIRI(followingURI) person.SetActivityStreamsFollowing(followingProp) // followers // The URI for retrieving a list of this user's followers followersProp := streams.NewActivityStreamsFollowersProperty() followersProp.SetIRI(followersURI) person.SetActivityStreamsFollowers(followersProp) // inbox // the activitypub inbox of this user for accepting messages inboxProp := streams.NewActivityStreamsInboxProperty() inboxProp.SetIRI(inboxURI) person.SetActivityStreamsInbox(inboxProp) // shared inbox if sharedInboxIRI != nil { endpointsProp := streams.NewActivityStreamsEndpointsProperty() endpoints := streams.NewActivityStreamsEndpoints() sharedInboxProp := streams.NewActivityStreamsSharedInboxProperty() sharedInboxProp.SetIRI(sharedInboxIRI) endpoints.SetActivityStreamsSharedInbox(sharedInboxProp) endpointsProp.AppendActivityStreamsEndpoints(endpoints) person.SetActivityStreamsEndpoints(endpointsProp) } // outbox // the activitypub outbox of this user for serving messages outboxProp := streams.NewActivityStreamsOutboxProperty() outboxProp.SetIRI(outboxURI) person.SetActivityStreamsOutbox(outboxProp) // featured posts // Pinned posts. featuredProp := streams.NewTootFeaturedProperty() featuredProp.SetIRI(featuredURI) person.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) person.SetActivityStreamsPreferredUsername(preferredUsernameProp) // name // Used as profile display name. nameProp := streams.NewActivityStreamsNameProperty() if displayName != "" { nameProp.AppendXMLSchemaString(displayName) } else { nameProp.AppendXMLSchemaString(username) } person.SetActivityStreamsName(nameProp) // summary // Used as profile bio. if note != "" { summaryProp := streams.NewActivityStreamsSummaryProperty() summaryProp.AppendXMLSchemaString(note) person.SetActivityStreamsSummary(summaryProp) } // url // Used as profile link. urlProp := streams.NewActivityStreamsUrlProperty() urlProp.AppendIRI(profileURL) person.SetActivityStreamsUrl(urlProp) // manuallyApprovesFollowers manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers) person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) // discoverable // Will be shown in the profile directory. discoverableProp := streams.NewTootDiscoverableProperty() discoverableProp.Set(discoverable) person.SetTootDiscoverable(discoverableProp) // devices // NOT IMPLEMENTED, probably won't implement // alsoKnownAs, movedTo // Required for Move activity. if len(alsoKnownAsURIs) != 0 { ap.SetAlsoKnownAs(person, alsoKnownAsURIs) } if movedToURI != nil { ap.SetMovedTo(person, movedToURI) } // 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 person.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) person.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) person.SetActivityStreamsImage(headerProperty) return person } func newAPGroup( 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.ActivityStreamsGroup { group := streams.NewActivityStreamsGroup() // id should be the activitypub URI of this group // something like https://example.org/users/example_group idProp := streams.NewJSONLDIdProperty() idProp.SetIRI(profileIDURI) group.SetJSONLDId(idProp) // following // The URI for retrieving a list of accounts this group is following followingProp := streams.NewActivityStreamsFollowingProperty() followingProp.SetIRI(followingURI) group.SetActivityStreamsFollowing(followingProp) // followers // The URI for retrieving a list of this user's followers followersProp := streams.NewActivityStreamsFollowersProperty() followersProp.SetIRI(followersURI) group.SetActivityStreamsFollowers(followersProp) // inbox // the activitypub inbox of this user for accepting messages inboxProp := streams.NewActivityStreamsInboxProperty() inboxProp.SetIRI(inboxURI) group.SetActivityStreamsInbox(inboxProp) // outbox // the activitypub outbox of this user for serving messages outboxProp := streams.NewActivityStreamsOutboxProperty() outboxProp.SetIRI(outboxURI) group.SetActivityStreamsOutbox(outboxProp) // featured posts // Pinned posts. featuredProp := streams.NewTootFeaturedProperty() featuredProp.SetIRI(featuredURI) group.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) group.SetActivityStreamsPreferredUsername(preferredUsernameProp) // name // Used as profile display name. nameProp := streams.NewActivityStreamsNameProperty() if displayName != "" { nameProp.AppendXMLSchemaString(displayName) } else { nameProp.AppendXMLSchemaString(username) } group.SetActivityStreamsName(nameProp) // summary // Used as profile bio. if note != "" { summaryProp := streams.NewActivityStreamsSummaryProperty() summaryProp.AppendXMLSchemaString(note) group.SetActivityStreamsSummary(summaryProp) } // url // Used as profile link. urlProp := streams.NewActivityStreamsUrlProperty() urlProp.AppendIRI(profileURL) group.SetActivityStreamsUrl(urlProp) // manuallyApprovesFollowers manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers) group.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) // discoverable // Will be shown in the profile directory. discoverableProp := streams.NewTootDiscoverableProperty() discoverableProp.Set(discoverable) group.SetTootDiscoverable(discoverableProp) // devices // NOT IMPLEMENTED, probably won't implement // AlsoKnownAsURI // 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 group.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) group.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) group.SetActivityStreamsImage(headerProperty) 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 // AlsoKnownAsURI // 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() hrefProp := streams.NewActivityStreamsHrefProperty() hrefProp.SetIRI(uri) mention.SetActivityStreamsHref(hrefProp) nameProp := streams.NewActivityStreamsNameProperty() nameProp.AppendXMLSchemaString(namestring) mention.SetActivityStreamsName(nameProp) return mention } func newAPHashtag(href *url.URL, name string) vocab.TootHashtag { hashtag := streams.NewTootHashtag() hrefProp := streams.NewActivityStreamsHrefProperty() hrefProp.SetIRI(href) hashtag.SetActivityStreamsHref(hrefProp) nameProp := streams.NewActivityStreamsNameProperty() nameProp.AppendXMLSchemaString(name) hashtag.SetActivityStreamsName(nameProp) return hashtag } func newAPImage(url *url.URL, mediaType string, imageDescription string, blurhash string) vocab.ActivityStreamsImage { image := streams.NewActivityStreamsImage() if url != nil { urlProp := streams.NewActivityStreamsUrlProperty() urlProp.AppendIRI(url) image.SetActivityStreamsUrl(urlProp) } if mediaType != "" { mediaTypeProp := streams.NewActivityStreamsMediaTypeProperty() mediaTypeProp.Set(mediaType) image.SetActivityStreamsMediaType(mediaTypeProp) } if imageDescription != "" { nameProp := streams.NewActivityStreamsNameProperty() nameProp.AppendXMLSchemaString(imageDescription) image.SetActivityStreamsName(nameProp) } if blurhash != "" { blurhashProp := streams.NewTootBlurhashProperty() blurhashProp.Set(blurhash) image.SetTootBlurhash(blurhashProp) } return image } func newAPEmoji(id *url.URL, name string, updated time.Time, image vocab.ActivityStreamsImage) vocab.TootEmoji { emoji := streams.NewTootEmoji() idProp := streams.NewJSONLDIdProperty() idProp.SetIRI(id) emoji.SetJSONLDId(idProp) nameProp := streams.NewActivityStreamsNameProperty() nameProp.AppendXMLSchemaString(`:` + strings.Trim(name, ":") + `:`) emoji.SetActivityStreamsName(nameProp) updatedProp := streams.NewActivityStreamsUpdatedProperty() updatedProp.Set(updated) emoji.SetActivityStreamsUpdated(updatedProp) iconProp := streams.NewActivityStreamsIconProperty() iconProp.AppendActivityStreamsImage(image) emoji.SetActivityStreamsIcon(iconProp) return emoji } // NewAPNote returns a new activity streams note for the given parameters func NewAPNote( noteID *url.URL, noteURL *url.URL, noteCreatedAt time.Time, noteContent string, noteSummary string, noteAttributedTo *url.URL, noteTo []*url.URL, noteCC []*url.URL, noteSensitive bool, noteMentions []vocab.ActivityStreamsMention, noteTags []vocab.TootHashtag, noteAttachments []vocab.ActivityStreamsImage, ) vocab.ActivityStreamsNote { // create the note itself note := streams.NewActivityStreamsNote() // set id if noteID != nil { id := streams.NewJSONLDIdProperty() id.Set(noteID) note.SetJSONLDId(id) } // set noteURL if noteURL != nil { url := streams.NewActivityStreamsUrlProperty() url.AppendIRI(noteURL) note.SetActivityStreamsUrl(url) } published := streams.NewActivityStreamsPublishedProperty() published.Set(noteCreatedAt) note.SetActivityStreamsPublished(published) // set noteContent if noteContent != "" { content := streams.NewActivityStreamsContentProperty() content.AppendXMLSchemaString(noteContent) note.SetActivityStreamsContent(content) } // set noteSummary (aka content warning) if noteSummary != "" { summary := streams.NewActivityStreamsSummaryProperty() summary.AppendXMLSchemaString(noteSummary) note.SetActivityStreamsSummary(summary) } // set noteAttributedTo (the url of the author of the note) if noteAttributedTo != nil { attributedTo := streams.NewActivityStreamsAttributedToProperty() attributedTo.AppendIRI(noteAttributedTo) note.SetActivityStreamsAttributedTo(attributedTo) } // set noteTO if noteTo != nil { to := streams.NewActivityStreamsToProperty() for _, r := range noteTo { to.AppendIRI(r) } note.SetActivityStreamsTo(to) } // set noteCC if noteCC != nil { cc := streams.NewActivityStreamsCcProperty() for _, r := range noteCC { cc.AppendIRI(r) } note.SetActivityStreamsCc(cc) } // Tag entries tag := streams.NewActivityStreamsTagProperty() // mentions for _, m := range noteMentions { tag.AppendActivityStreamsMention(m) } note.SetActivityStreamsTag(tag) // hashtags for _, t := range noteTags { tag.AppendTootHashtag(t) } // append any attachments as ActivityStreamsImage if noteAttachments != nil { attachmentProperty := streams.NewActivityStreamsAttachmentProperty() for _, a := range noteAttachments { attachmentProperty.AppendActivityStreamsImage(a) } note.SetActivityStreamsAttachment(attachmentProperty) } return note } // WrapAPNoteInCreate wraps the given activity streams note in a Create activity streams action func WrapAPNoteInCreate(createID *url.URL, createActor *url.URL, createPublished time.Time, createNote vocab.ActivityStreamsNote) vocab.ActivityStreamsCreate { // create the.... create create := streams.NewActivityStreamsCreate() // set createID if createID != nil { id := streams.NewJSONLDIdProperty() id.Set(createID) create.SetJSONLDId(id) } // set createActor if createActor != nil { actor := streams.NewActivityStreamsActorProperty() actor.AppendIRI(createActor) create.SetActivityStreamsActor(actor) } // set createPublished (time) if !createPublished.IsZero() { published := streams.NewActivityStreamsPublishedProperty() published.Set(createPublished) create.SetActivityStreamsPublished(published) } // setCreateTo if createNote.GetActivityStreamsTo() != nil { create.SetActivityStreamsTo(createNote.GetActivityStreamsTo()) } // setCreateCC if createNote.GetActivityStreamsCc() != nil { create.SetActivityStreamsCc(createNote.GetActivityStreamsCc()) } // set createNote if createNote != nil { note := streams.NewActivityStreamsObjectProperty() note.AppendActivityStreamsNote(createNote) create.SetActivityStreamsObject(note) } return create } func newAPAnnounce(announceID *url.URL, announceActor *url.URL, announcePublished time.Time, announceTo *url.URL, announceNote vocab.ActivityStreamsNote) vocab.ActivityStreamsAnnounce { announce := streams.NewActivityStreamsAnnounce() if announceID != nil { id := streams.NewJSONLDIdProperty() id.Set(announceID) announce.SetJSONLDId(id) } if announceActor != nil { actor := streams.NewActivityStreamsActorProperty() actor.AppendIRI(announceActor) announce.SetActivityStreamsActor(actor) } if !announcePublished.IsZero() { published := streams.NewActivityStreamsPublishedProperty() published.Set(announcePublished) announce.SetActivityStreamsPublished(published) } to := streams.NewActivityStreamsToProperty() to.AppendIRI(announceTo) announce.SetActivityStreamsTo(announceNote.GetActivityStreamsTo()) cc := streams.NewActivityStreamsCcProperty() cc.AppendIRI(announceNote.GetActivityStreamsAttributedTo().Begin().GetIRI()) announce.SetActivityStreamsCc(cc) if announceNote != nil { noteIRI := streams.NewActivityStreamsObjectProperty() noteIRI.AppendIRI(announceNote.GetJSONLDId().Get()) announce.SetActivityStreamsObject(noteIRI) } return announce } func newAPDelete(deleteTarget *url.URL, deleteActor *url.URL, deletePublished time.Time, deleteTo *url.URL) vocab.ActivityStreamsDelete { delete := streams.NewActivityStreamsDelete() objectProp := streams.NewActivityStreamsObjectProperty() objectProp.AppendIRI(deleteTarget) delete.SetActivityStreamsObject(objectProp) to := streams.NewActivityStreamsToProperty() to.AppendIRI(deleteTo) delete.SetActivityStreamsTo(to) actor := streams.NewActivityStreamsActorProperty() actor.AppendIRI(deleteActor) delete.SetActivityStreamsActor(actor) published := streams.NewActivityStreamsPublishedProperty() published.Set(deletePublished) delete.SetActivityStreamsPublished(published) return delete }