testmodels.go (160167B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package testrig 19 20 import ( 21 "bytes" 22 "crypto/rand" 23 "crypto/rsa" 24 "crypto/x509" 25 "encoding/base64" 26 "encoding/json" 27 "encoding/pem" 28 "fmt" 29 "net" 30 "net/http" 31 "net/url" 32 "os" 33 "sort" 34 "strings" 35 "time" 36 37 "github.com/superseriousbusiness/activity/pub" 38 "github.com/superseriousbusiness/activity/streams" 39 "github.com/superseriousbusiness/activity/streams/vocab" 40 "github.com/superseriousbusiness/gotosocial/internal/ap" 41 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 42 "github.com/superseriousbusiness/gotosocial/internal/transport" 43 ) 44 45 // TrueBool just returns a pointer to boolean true. 46 func TrueBool() *bool { 47 b := new(bool) 48 *b = true 49 return b 50 } 51 52 // FalseBool just returns a pointer to boolean false. 53 func FalseBool() *bool { 54 return new(bool) 55 } 56 57 // StringPtr returns a pointer to the given string. 58 func StringPtr(in string) *string { 59 return &in 60 } 61 62 func Float32Ptr(in float32) *float32 { 63 return &in 64 } 65 66 func Uint64Ptr(in uint64) *uint64 { 67 return &in 68 } 69 70 // NewTestTokens returns a map of tokens keyed according to which account the token belongs to. 71 func NewTestTokens() map[string]*gtsmodel.Token { 72 tokens := map[string]*gtsmodel.Token{ 73 "local_account_1": { 74 ID: "01F8MGTQW4DKTDF8SW5CT9HYGA", 75 ClientID: "01F8MGV8AC3NGSJW0FE8W1BV70", 76 UserID: "01F8MGVGPHQ2D3P3X0454H54Z5", 77 RedirectURI: "http://localhost:8080", 78 Scope: "read write follow push", 79 Access: "NZAZOTC0OWITMDU0NC0ZODG4LWE4NJITMWUXM2M4MTRHZDEX", 80 AccessCreateAt: TimeMustParse("2022-06-10T15:22:08Z"), 81 AccessExpiresAt: TimeMustParse("2050-01-01T15:22:08Z"), 82 }, 83 "local_account_1_client_application_token": { 84 ID: "01P9SVWS9J3SPHZQ3KCMBEN70N", 85 ClientID: "01F8MGV8AC3NGSJW0FE8W1BV70", 86 RedirectURI: "http://localhost:8080", 87 Access: "ZTK1MWMWZDGTMGMXOS0ZY2UXLWI5ZWETMWEZYZZIYTLHMZI4", 88 AccessCreateAt: TimeMustParse("2022-06-10T15:22:08Z"), 89 AccessExpiresAt: TimeMustParse("2050-01-01T15:22:08Z"), 90 }, 91 "local_account_1_user_authorization_token": { 92 ID: "01G574M2VTV66YZBC9AZ7HY3FV", 93 ClientID: "01F8MGV8AC3NGSJW0FE8W1BV70", 94 UserID: "01F8MGVGPHQ2D3P3X0454H54Z5", 95 RedirectURI: "http://localhost:8080", 96 Code: "ZJYYMZQ0MTQTZTU1NC0ZNJK4LWE2ZWITYTM1MDHHOTAXNJHL", 97 CodeCreateAt: TimeMustParse("2022-06-10T15:22:08Z"), 98 CodeExpiresAt: TimeMustParse("2050-01-01T15:22:08Z"), 99 }, 100 "local_account_2": { 101 ID: "01F8MGVVM1EDVYET710J27XY5R", 102 ClientID: "01F8MGW47HN8ZXNHNZ7E47CDMQ", 103 UserID: "01F8MH1VYJAE00TVVGMM5JNJ8X", 104 RedirectURI: "http://localhost:8080", 105 Scope: "read write follow push", 106 Access: "PIPINALKNNNFNF98717NAMNAMNFKIJKJ881818KJKJAKJJJA", 107 AccessCreateAt: TimeMustParse("2022-06-10T15:22:08Z"), 108 AccessExpiresAt: TimeMustParse("2050-01-01T15:22:08Z"), 109 }, 110 "admin_account": { 111 ID: "01FS4TP8ANA5VE92EAPA9E0M7Q", 112 ClientID: "01F8MGWSJCND9BWBD4WGJXBM93", 113 UserID: "01F8MGWYWKVKS3VS8DV1AMYPGE", 114 RedirectURI: "http://localhost:8080", 115 Scope: "read write follow push admin", 116 Access: "AININALKNENFNF98717NAMG4LWE4NJITMWUXM2M4MTRHZDEX", 117 AccessCreateAt: TimeMustParse("2022-06-10T15:22:08Z"), 118 AccessExpiresAt: TimeMustParse("2050-01-01T15:22:08Z"), 119 }, 120 } 121 return tokens 122 } 123 124 // NewTestClients returns a map of Clients keyed according to which account they are used by. 125 func NewTestClients() map[string]*gtsmodel.Client { 126 clients := map[string]*gtsmodel.Client{ 127 "admin_account": { 128 ID: "01F8MGWSJCND9BWBD4WGJXBM93", 129 Secret: "dda8e835-2c9c-4bd2-9b8b-77c2e26d7a7a", 130 Domain: "http://localhost:8080", 131 UserID: "01F8MGWYWKVKS3VS8DV1AMYPGE", // admin_account 132 }, 133 "local_account_1": { 134 ID: "01F8MGV8AC3NGSJW0FE8W1BV70", 135 Secret: "c3724c74-dc3b-41b2-a108-0ea3d8399830", 136 Domain: "http://localhost:8080", 137 UserID: "01F8MGVGPHQ2D3P3X0454H54Z5", // local_account_1 138 }, 139 "local_account_2": { 140 ID: "01F8MGW47HN8ZXNHNZ7E47CDMQ", 141 Secret: "8f5603a5-c721-46cd-8f1b-2e368f51379f", 142 Domain: "http://localhost:8080", 143 UserID: "01F8MH1VYJAE00TVVGMM5JNJ8X", // local_account_2 144 }, 145 } 146 return clients 147 } 148 149 // NewTestApplications returns a map of applications keyed to which number application they are. 150 func NewTestApplications() map[string]*gtsmodel.Application { 151 apps := map[string]*gtsmodel.Application{ 152 "admin_account": { 153 ID: "01F8MGXQRHYF5QPMTMXP78QC2F", 154 Name: "superseriousbusiness", 155 Website: "https://superserious.business", 156 RedirectURI: "http://localhost:8080", 157 ClientID: "01F8MGWSJCND9BWBD4WGJXBM93", // admin client 158 ClientSecret: "dda8e835-2c9c-4bd2-9b8b-77c2e26d7a7a", // admin client 159 Scopes: "read write follow push", 160 }, 161 "application_1": { 162 ID: "01F8MGY43H3N2C8EWPR2FPYEXG", 163 Name: "really cool gts application", 164 Website: "https://reallycool.app", 165 RedirectURI: "http://localhost:8080", 166 ClientID: "01F8MGV8AC3NGSJW0FE8W1BV70", // client_1 167 ClientSecret: "c3724c74-dc3b-41b2-a108-0ea3d8399830", // client_1 168 Scopes: "read write follow push", 169 }, 170 "application_2": { 171 ID: "01F8MGYG9E893WRHW0TAEXR8GJ", 172 Name: "kindaweird", 173 Website: "https://kindaweird.app", 174 RedirectURI: "http://localhost:8080", 175 ClientID: "01F8MGW47HN8ZXNHNZ7E47CDMQ", // client_2 176 ClientSecret: "8f5603a5-c721-46cd-8f1b-2e368f51379f", // client_2 177 Scopes: "read write follow push", 178 }, 179 } 180 return apps 181 } 182 183 // NewTestUsers returns a map of Users keyed by which account belongs to them. 184 func NewTestUsers() map[string]*gtsmodel.User { 185 users := map[string]*gtsmodel.User{ 186 "unconfirmed_account": { 187 ID: "01F8MGYG9E893WRHW0TAEXR8GJ", 188 Email: "", 189 AccountID: "01F8MH0BBE4FHXPH513MBVFHB0", 190 EncryptedPassword: "$2y$10$ggWz5QWwnx6kzb9g0tnIJurFtE0dhr5Zfeaqs9iFuUIXzafQlJVZS", // 'password' 191 CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 192 SignUpIP: net.ParseIP("199.222.111.89"), 193 UpdatedAt: time.Time{}, 194 CurrentSignInAt: time.Time{}, 195 CurrentSignInIP: nil, 196 LastSignInAt: time.Time{}, 197 LastSignInIP: nil, 198 SignInCount: 0, 199 InviteID: "", 200 ChosenLanguages: []string{}, 201 FilteredLanguages: []string{}, 202 Locale: "en", 203 CreatedByApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 204 LastEmailedAt: time.Time{}, 205 ConfirmationToken: "a5a280bd-34be-44a3-8330-a57eaf61b8dd", 206 ConfirmedAt: time.Time{}, 207 ConfirmationSentAt: TimeMustParse("2022-06-04T13:12:00Z"), 208 UnconfirmedEmail: "weed_lord420@example.org", 209 Moderator: FalseBool(), 210 Admin: FalseBool(), 211 Disabled: FalseBool(), 212 Approved: FalseBool(), 213 ResetPasswordToken: "", 214 ResetPasswordSentAt: time.Time{}, 215 }, 216 "admin_account": { 217 ID: "01F8MGWYWKVKS3VS8DV1AMYPGE", 218 Email: "admin@example.org", 219 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 220 EncryptedPassword: "$2y$10$ggWz5QWwnx6kzb9g0tnIJurFtE0dhr5Zfeaqs9iFuUIXzafQlJVZS", // 'password' 221 CreatedAt: TimeMustParse("2022-06-01T13:12:00Z"), 222 SignUpIP: net.ParseIP("89.22.189.19"), 223 UpdatedAt: TimeMustParse("2022-06-01T13:12:00Z"), 224 CurrentSignInAt: TimeMustParse("2022-06-04T13:12:00Z"), 225 CurrentSignInIP: net.ParseIP("89.122.255.1"), 226 LastSignInAt: TimeMustParse("2022-06-03T13:12:00Z"), 227 LastSignInIP: net.ParseIP("89.122.255.1"), 228 SignInCount: 78, 229 InviteID: "", 230 ChosenLanguages: []string{"en"}, 231 FilteredLanguages: []string{}, 232 Locale: "en", 233 CreatedByApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 234 LastEmailedAt: TimeMustParse("2022-06-03T13:12:00Z"), 235 ConfirmationToken: "", 236 ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"), 237 ConfirmationSentAt: time.Time{}, 238 UnconfirmedEmail: "", 239 Moderator: TrueBool(), 240 Admin: TrueBool(), 241 Disabled: FalseBool(), 242 Approved: TrueBool(), 243 ResetPasswordToken: "", 244 ResetPasswordSentAt: time.Time{}, 245 }, 246 "local_account_1": { 247 ID: "01F8MGVGPHQ2D3P3X0454H54Z5", 248 Email: "zork@example.org", 249 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 250 EncryptedPassword: "$2y$10$ggWz5QWwnx6kzb9g0tnIJurFtE0dhr5Zfeaqs9iFuUIXzafQlJVZS", // 'password' 251 CreatedAt: TimeMustParse("2022-06-01T13:12:00Z"), 252 SignUpIP: net.ParseIP("59.99.19.172"), 253 UpdatedAt: TimeMustParse("2022-06-01T13:12:00Z"), 254 CurrentSignInAt: TimeMustParse("2022-06-04T13:12:00Z"), 255 CurrentSignInIP: net.ParseIP("88.234.118.16"), 256 LastSignInAt: TimeMustParse("2022-06-03T13:12:00Z"), 257 LastSignInIP: net.ParseIP("147.111.231.154"), 258 SignInCount: 9, 259 InviteID: "", 260 ChosenLanguages: []string{"en"}, 261 FilteredLanguages: []string{}, 262 Locale: "en", 263 CreatedByApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 264 LastEmailedAt: TimeMustParse("2022-06-02T13:12:00Z"), 265 ConfirmationToken: "", 266 ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"), 267 ConfirmationSentAt: TimeMustParse("2022-06-02T13:12:00Z"), 268 UnconfirmedEmail: "", 269 Moderator: FalseBool(), 270 Admin: FalseBool(), 271 Disabled: FalseBool(), 272 Approved: TrueBool(), 273 ResetPasswordToken: "", 274 ResetPasswordSentAt: time.Time{}, 275 }, 276 "local_account_2": { 277 ID: "01F8MH1VYJAE00TVVGMM5JNJ8X", 278 Email: "tortle.dude@example.org", 279 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 280 EncryptedPassword: "$2y$10$ggWz5QWwnx6kzb9g0tnIJurFtE0dhr5Zfeaqs9iFuUIXzafQlJVZS", // 'password' 281 CreatedAt: TimeMustParse("2022-05-23T13:12:00Z"), 282 SignUpIP: net.ParseIP("59.99.19.172"), 283 UpdatedAt: TimeMustParse("2022-05-23T13:12:00Z"), 284 CurrentSignInAt: TimeMustParse("2022-06-05T13:12:00Z"), 285 CurrentSignInIP: net.ParseIP("118.44.18.196"), 286 LastSignInAt: TimeMustParse("2022-06-06T13:12:00Z"), 287 LastSignInIP: net.ParseIP("198.98.21.15"), 288 SignInCount: 9, 289 InviteID: "", 290 ChosenLanguages: []string{"en"}, 291 FilteredLanguages: []string{}, 292 Locale: "en", 293 CreatedByApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 294 LastEmailedAt: TimeMustParse("2022-06-06T13:12:00Z"), 295 ConfirmationToken: "", 296 ConfirmedAt: TimeMustParse("2022-05-24T13:12:00Z"), 297 ConfirmationSentAt: TimeMustParse("2022-05-23T13:12:00Z"), 298 UnconfirmedEmail: "", 299 Moderator: FalseBool(), 300 Admin: FalseBool(), 301 Disabled: FalseBool(), 302 Approved: TrueBool(), 303 ResetPasswordToken: "", 304 ResetPasswordSentAt: time.Time{}, 305 }, 306 } 307 308 return users 309 } 310 311 // NewTestAccounts returns a map of accounts keyed by what type of account they are. 312 func NewTestAccounts() map[string]*gtsmodel.Account { 313 accounts := map[string]*gtsmodel.Account{ 314 "instance_account": { 315 ID: "01AY6P665V14JJR0AFVRT7311Y", 316 Username: "localhost:8080", 317 AvatarMediaAttachmentID: "", 318 HeaderMediaAttachmentID: "", 319 DisplayName: "", 320 Fields: []*gtsmodel.Field{}, 321 Note: "", 322 NoteRaw: "", 323 Memorial: FalseBool(), 324 MovedToAccountID: "", 325 CreatedAt: TimeMustParse("2020-05-17T13:10:59Z"), 326 UpdatedAt: TimeMustParse("2020-05-17T13:10:59Z"), 327 Bot: FalseBool(), 328 Reason: "", 329 Locked: FalseBool(), 330 Discoverable: TrueBool(), 331 Privacy: gtsmodel.VisibilityPublic, 332 Sensitive: FalseBool(), 333 Language: "en", 334 URI: "http://localhost:8080/users/localhost:8080", 335 URL: "http://localhost:8080/@localhost:8080", 336 PublicKeyURI: "http://localhost:8080/users/localhost:8080#main-key", 337 FetchedAt: time.Time{}, 338 InboxURI: "http://localhost:8080/users/localhost:8080/inbox", 339 OutboxURI: "http://localhost:8080/users/localhost:8080/outbox", 340 FollowersURI: "http://localhost:8080/users/localhost:8080/followers", 341 FollowingURI: "http://localhost:8080/users/localhost:8080/following", 342 FeaturedCollectionURI: "http://localhost:8080/users/localhost:8080/collections/featured", 343 ActorType: ap.ActorPerson, 344 AlsoKnownAs: "", 345 PrivateKey: &rsa.PrivateKey{}, 346 PublicKey: &rsa.PublicKey{}, 347 SensitizedAt: time.Time{}, 348 SilencedAt: time.Time{}, 349 SuspendedAt: time.Time{}, 350 HideCollections: FalseBool(), 351 SuspensionOrigin: "", 352 EnableRSS: FalseBool(), 353 }, 354 "unconfirmed_account": { 355 ID: "01F8MH0BBE4FHXPH513MBVFHB0", 356 Username: "weed_lord420", 357 AvatarMediaAttachmentID: "", 358 HeaderMediaAttachmentID: "", 359 DisplayName: "", 360 Fields: []*gtsmodel.Field{}, 361 Note: "", 362 Memorial: FalseBool(), 363 MovedToAccountID: "", 364 CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 365 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 366 Bot: FalseBool(), 367 Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.", 368 Locked: FalseBool(), 369 Discoverable: FalseBool(), 370 Privacy: gtsmodel.VisibilityPublic, 371 Sensitive: FalseBool(), 372 Language: "en", 373 URI: "http://localhost:8080/users/weed_lord420", 374 URL: "http://localhost:8080/@weed_lord420", 375 FetchedAt: time.Time{}, 376 InboxURI: "http://localhost:8080/users/weed_lord420/inbox", 377 OutboxURI: "http://localhost:8080/users/weed_lord420/outbox", 378 FollowersURI: "http://localhost:8080/users/weed_lord420/followers", 379 FollowingURI: "http://localhost:8080/users/weed_lord420/following", 380 FeaturedCollectionURI: "http://localhost:8080/users/weed_lord420/collections/featured", 381 ActorType: ap.ActorPerson, 382 AlsoKnownAs: "", 383 PrivateKey: &rsa.PrivateKey{}, 384 PublicKey: &rsa.PublicKey{}, 385 PublicKeyURI: "http://localhost:8080/users/weed_lord420#main-key", 386 SensitizedAt: time.Time{}, 387 SilencedAt: time.Time{}, 388 SuspendedAt: time.Time{}, 389 HideCollections: FalseBool(), 390 SuspensionOrigin: "", 391 }, 392 "admin_account": { 393 ID: "01F8MH17FWEB39HZJ76B6VXSKF", 394 Username: "admin", 395 AvatarMediaAttachmentID: "", 396 HeaderMediaAttachmentID: "", 397 DisplayName: "", 398 Fields: []*gtsmodel.Field{}, 399 Note: "", 400 NoteRaw: "", 401 Memorial: FalseBool(), 402 MovedToAccountID: "", 403 CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"), 404 UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"), 405 Bot: FalseBool(), 406 Reason: "", 407 Locked: FalseBool(), 408 Discoverable: TrueBool(), 409 Privacy: gtsmodel.VisibilityPublic, 410 Sensitive: FalseBool(), 411 Language: "en", 412 URI: "http://localhost:8080/users/admin", 413 URL: "http://localhost:8080/@admin", 414 PublicKeyURI: "http://localhost:8080/users/admin#main-key", 415 FetchedAt: time.Time{}, 416 InboxURI: "http://localhost:8080/users/admin/inbox", 417 OutboxURI: "http://localhost:8080/users/admin/outbox", 418 FollowersURI: "http://localhost:8080/users/admin/followers", 419 FollowingURI: "http://localhost:8080/users/admin/following", 420 FeaturedCollectionURI: "http://localhost:8080/users/admin/collections/featured", 421 ActorType: ap.ActorPerson, 422 AlsoKnownAs: "", 423 PrivateKey: &rsa.PrivateKey{}, 424 PublicKey: &rsa.PublicKey{}, 425 SensitizedAt: time.Time{}, 426 SilencedAt: time.Time{}, 427 SuspendedAt: time.Time{}, 428 HideCollections: FalseBool(), 429 SuspensionOrigin: "", 430 EnableRSS: TrueBool(), 431 }, 432 "local_account_1": { 433 ID: "01F8MH1H7YV1Z7D2C8K2730QBF", 434 Username: "the_mighty_zork", 435 AvatarMediaAttachmentID: "01F8MH58A357CV5K7R7TJMSH6S", 436 HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3Q", 437 DisplayName: "original zork (he/they)", 438 Fields: []*gtsmodel.Field{}, 439 Note: "<p>hey yo this is my profile!</p>", 440 NoteRaw: "hey yo this is my profile!", 441 Memorial: FalseBool(), 442 MovedToAccountID: "", 443 CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"), 444 UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"), 445 Bot: FalseBool(), 446 Reason: "I wanna be on this damned webbed site so bad! Please! Wow", 447 Locked: FalseBool(), 448 Discoverable: TrueBool(), 449 Privacy: gtsmodel.VisibilityPublic, 450 Sensitive: FalseBool(), 451 Language: "en", 452 URI: "http://localhost:8080/users/the_mighty_zork", 453 URL: "http://localhost:8080/@the_mighty_zork", 454 FetchedAt: time.Time{}, 455 InboxURI: "http://localhost:8080/users/the_mighty_zork/inbox", 456 OutboxURI: "http://localhost:8080/users/the_mighty_zork/outbox", 457 FollowersURI: "http://localhost:8080/users/the_mighty_zork/followers", 458 FollowingURI: "http://localhost:8080/users/the_mighty_zork/following", 459 FeaturedCollectionURI: "http://localhost:8080/users/the_mighty_zork/collections/featured", 460 ActorType: ap.ActorPerson, 461 AlsoKnownAs: "", 462 PrivateKey: &rsa.PrivateKey{}, 463 PublicKey: &rsa.PublicKey{}, 464 PublicKeyURI: "http://localhost:8080/users/the_mighty_zork/main-key", 465 SensitizedAt: time.Time{}, 466 SilencedAt: time.Time{}, 467 SuspendedAt: time.Time{}, 468 HideCollections: FalseBool(), 469 SuspensionOrigin: "", 470 EnableRSS: TrueBool(), 471 }, 472 "local_account_2": { 473 ID: "01F8MH5NBDF2MV7CTC4Q5128HF", 474 Username: "1happyturtle", 475 AvatarMediaAttachmentID: "", 476 HeaderMediaAttachmentID: "", 477 DisplayName: "happy little turtle :3", 478 Fields: []*gtsmodel.Field{ 479 { 480 Name: "should you follow me?", 481 Value: "maybe!", 482 }, 483 { 484 Name: "age", 485 Value: "120", 486 }, 487 }, 488 FieldsRaw: []*gtsmodel.Field{ 489 { 490 Name: "should you follow me?", 491 Value: "maybe!", 492 }, 493 { 494 Name: "age", 495 Value: "120", 496 }, 497 }, 498 Note: "<p>i post about things that concern me</p>", 499 NoteRaw: "i post about things that concern me", 500 Memorial: FalseBool(), 501 MovedToAccountID: "", 502 CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 503 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 504 Bot: FalseBool(), 505 Reason: "", 506 Locked: TrueBool(), 507 Discoverable: FalseBool(), 508 Privacy: gtsmodel.VisibilityFollowersOnly, 509 Sensitive: TrueBool(), 510 Language: "fr", 511 URI: "http://localhost:8080/users/1happyturtle", 512 URL: "http://localhost:8080/@1happyturtle", 513 FetchedAt: time.Time{}, 514 InboxURI: "http://localhost:8080/users/1happyturtle/inbox", 515 OutboxURI: "http://localhost:8080/users/1happyturtle/outbox", 516 FollowersURI: "http://localhost:8080/users/1happyturtle/followers", 517 FollowingURI: "http://localhost:8080/users/1happyturtle/following", 518 FeaturedCollectionURI: "http://localhost:8080/users/1happyturtle/collections/featured", 519 ActorType: ap.ActorPerson, 520 AlsoKnownAs: "", 521 PrivateKey: &rsa.PrivateKey{}, 522 PublicKey: &rsa.PublicKey{}, 523 PublicKeyURI: "http://localhost:8080/users/1happyturtle#main-key", 524 SensitizedAt: time.Time{}, 525 SilencedAt: time.Time{}, 526 SuspendedAt: time.Time{}, 527 HideCollections: FalseBool(), 528 SuspensionOrigin: "", 529 EnableRSS: FalseBool(), 530 }, 531 "remote_account_1": { 532 ID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 533 Username: "foss_satan", 534 Domain: "fossbros-anonymous.io", 535 DisplayName: "big gerald", 536 Fields: []*gtsmodel.Field{}, 537 Note: "i post about like, i dunno, stuff, or whatever!!!!", 538 Memorial: FalseBool(), 539 MovedToAccountID: "", 540 CreatedAt: TimeMustParse("2021-09-26T12:52:36+02:00"), 541 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 542 Bot: FalseBool(), 543 Locked: FalseBool(), 544 Discoverable: TrueBool(), 545 Sensitive: FalseBool(), 546 Language: "en", 547 URI: "http://fossbros-anonymous.io/users/foss_satan", 548 URL: "http://fossbros-anonymous.io/@foss_satan", 549 FetchedAt: time.Time{}, 550 InboxURI: "http://fossbros-anonymous.io/users/foss_satan/inbox", 551 SharedInboxURI: StringPtr("http://fossbros-anonymous.io/inbox"), 552 OutboxURI: "http://fossbros-anonymous.io/users/foss_satan/outbox", 553 FollowersURI: "http://fossbros-anonymous.io/users/foss_satan/followers", 554 FollowingURI: "http://fossbros-anonymous.io/users/foss_satan/following", 555 FeaturedCollectionURI: "http://fossbros-anonymous.io/users/foss_satan/collections/featured", 556 ActorType: ap.ActorPerson, 557 AlsoKnownAs: "", 558 PrivateKey: &rsa.PrivateKey{}, 559 PublicKey: &rsa.PublicKey{}, 560 PublicKeyURI: "http://fossbros-anonymous.io/users/foss_satan/main-key", 561 SensitizedAt: time.Time{}, 562 SilencedAt: time.Time{}, 563 SuspendedAt: time.Time{}, 564 HideCollections: FalseBool(), 565 SuspensionOrigin: "", 566 }, 567 "remote_account_2": { 568 ID: "01FHMQX3GAABWSM0S2VZEC2SWC", 569 Username: "Some_User", 570 Domain: "example.org", 571 DisplayName: "some user", 572 Fields: []*gtsmodel.Field{}, 573 Note: "i'm a real son of a gun", 574 Memorial: FalseBool(), 575 MovedToAccountID: "", 576 CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), 577 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 578 Bot: FalseBool(), 579 Locked: TrueBool(), 580 Discoverable: TrueBool(), 581 Sensitive: FalseBool(), 582 Language: "en", 583 URI: "http://example.org/users/Some_User", 584 URL: "http://example.org/@Some_User", 585 FetchedAt: time.Time{}, 586 InboxURI: "http://example.org/users/Some_User/inbox", 587 SharedInboxURI: StringPtr(""), 588 OutboxURI: "http://example.org/users/Some_User/outbox", 589 FollowersURI: "http://example.org/users/Some_User/followers", 590 FollowingURI: "http://example.org/users/Some_User/following", 591 FeaturedCollectionURI: "http://example.org/users/Some_User/collections/featured", 592 ActorType: ap.ActorPerson, 593 AlsoKnownAs: "", 594 PrivateKey: &rsa.PrivateKey{}, 595 PublicKey: &rsa.PublicKey{}, 596 PublicKeyURI: "http://example.org/users/Some_User#main-key", 597 SensitizedAt: time.Time{}, 598 SilencedAt: time.Time{}, 599 SuspendedAt: time.Time{}, 600 HideCollections: FalseBool(), 601 SuspensionOrigin: "", 602 }, 603 "remote_account_3": { 604 ID: "062G5WYKY35KKD12EMSM3F8PJ8", 605 Username: "her_fuckin_maj", 606 Domain: "thequeenisstillalive.technology", 607 DisplayName: "lizzzieeeeeeeeeeee", 608 Fields: []*gtsmodel.Field{}, 609 Note: "if i die blame charles don't let that fuck become king", 610 Memorial: FalseBool(), 611 MovedToAccountID: "", 612 CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), 613 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 614 Bot: FalseBool(), 615 Locked: TrueBool(), 616 Discoverable: TrueBool(), 617 Sensitive: FalseBool(), 618 Language: "en", 619 URI: "http://thequeenisstillalive.technology/users/her_fuckin_maj", 620 URL: "http://thequeenisstillalive.technology/@her_fuckin_maj", 621 FetchedAt: time.Time{}, 622 InboxURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/inbox", 623 SharedInboxURI: StringPtr(""), 624 OutboxURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/outbox", 625 FollowersURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/followers", 626 FollowingURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/following", 627 FeaturedCollectionURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj/collections/featured", 628 ActorType: ap.ActorPerson, 629 AlsoKnownAs: "", 630 PrivateKey: &rsa.PrivateKey{}, 631 PublicKey: &rsa.PublicKey{}, 632 PublicKeyURI: "http://thequeenisstillalive.technology/users/her_fuckin_maj#main-key", 633 SensitizedAt: time.Time{}, 634 SilencedAt: time.Time{}, 635 SuspendedAt: time.Time{}, 636 HideCollections: FalseBool(), 637 SuspensionOrigin: "", 638 HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3R", 639 }, 640 "remote_account_4": { 641 ID: "07GZRBAEMBNKGZ8Z9VSKSXKR98", 642 Username: "üser", 643 Domain: "xn--xample-ova.org", 644 DisplayName: "", 645 Note: "", 646 Memorial: FalseBool(), 647 MovedToAccountID: "", 648 CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), 649 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 650 Bot: FalseBool(), 651 Locked: FalseBool(), 652 Discoverable: FalseBool(), 653 Sensitive: FalseBool(), 654 Language: "de", 655 URI: "https://xn--xample-ova.org/users/%C3%BCser", 656 URL: "https://xn--xample-ova.org/users/@%C3%BCser", 657 FetchedAt: time.Time{}, 658 InboxURI: "https://xn--xample-ova.org/users/%C3%BCser/inbox", 659 SharedInboxURI: StringPtr(""), 660 OutboxURI: "https://xn--xample-ova.org/users/%C3%BCser/outbox", 661 FollowersURI: "https://xn--xample-ova.org/users/%C3%BCser/followers", 662 FollowingURI: "https://xn--xample-ova.org/users/%C3%BCser/following", 663 FeaturedCollectionURI: "https://xn--xample-ova.org/users/%C3%BCser/collections/featured", 664 ActorType: ap.ActorPerson, 665 AlsoKnownAs: "", 666 PrivateKey: &rsa.PrivateKey{}, 667 PublicKey: &rsa.PublicKey{}, 668 PublicKeyURI: "https://xn--xample-ova.org/users/%C3%BCser#main-key", 669 SensitizedAt: time.Time{}, 670 SilencedAt: time.Time{}, 671 SuspendedAt: time.Time{}, 672 HideCollections: FalseBool(), 673 SuspensionOrigin: "", 674 HeaderMediaAttachmentID: "", 675 EnableRSS: FalseBool(), 676 }, 677 } 678 679 var accountsSorted []*gtsmodel.Account 680 for _, a := range accounts { 681 accountsSorted = append(accountsSorted, a) 682 } 683 684 sort.Slice(accountsSorted, func(i, j int) bool { 685 return accountsSorted[i].ID > accountsSorted[j].ID 686 }) 687 688 preserializedKeys := []string{ 689 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/4BHKpxI7X+d6MKKnZtfi8F46sujkBS4HVXP/T/HfMqnwyeTOJMkSfJEbjSeJSyqxjrWKtaeO1vnduddPAgSj9kwaZ9Drf1KZA1zBCJp4ZPqQBQCUdQrWJHw87cCEGuFXObhgCvi8mM8gfBzmF5wz/K8USy/t3GCuAWgUwupAhN40Br1SgSwMv/LI2z04yZJN98SAxKDI8aRHEWd9LnyKSR08r581JEFTcqnqR14RvhC+3nXEYzU3HMND8QLsRXQFDmjeEpwiFPSo55iOToA/fLw0OC2v1v5OwUtuwjMr1mxMGG/QPPhCT5xKxTeIEvNtCcSBO2as3yAfYrJYL/T7AgMBAAECggEBALXCitgQAANizCJB5DL0B1ohHQI57Mfj6EBmQKYAkz09/yHr/uUQj7EFc2hIBMXYAK+GYo7tmbaECtpxa3aakM7JSDpTUeNkD1iHiNwLTFj0Py8irfP0E7nbgh0tk4sQ85nvQaspeYserkc1iyKkBwJwQWHV/6cxdhwflPrl0YYfM2TiSVauB+e/H+M/TzJMCKXMiN6bavJcsJT8m6b3sI1gGFdM+vylacGmrJ0PDroiE5LkjefYe8aGr1Gi+u8yl9n4c2qAR9TltUNV2SgC02J70B+IeS12xeLXKht8ayaAOpZcmggNAOATpEAUZ3qXnWYdu8rMChoNMnwUVJx0XiECgYEA2KgoA721ORR3AyWgVyc/ByyMFS/DGMOLXKBTsiH4Tt65bA7c2UKzcHtrmGbOcEHTD8h/FKoQ8TKhPFqAERyUZ1gwy6E6yuNDZOff5+4aPOszhNwW8ty0O0SrWTOVHyXnBYFAWCbzoKrGNsfxG6T6ZXzf1IYZZuyCc+lwz+Nb++MCgYEA4rfgz3+JwUga2jwWEKiQ+Oz2vuHh8lHRtjKTLvZePKBI5lFjS5PHNhs3JfN8kzhyh87CzcHpBFyeNPmc1WYr0hOuhoVk/8NC97BKvtxokafEXDhRbFlkNsgWb+gqkYZOAih6OL8FkC3yO6hqmLyX+zbN5ke3c0b3fHI4T/3qngkCgYBTS3L23TyLEV8gCps2ZpRIwcupaY9sOeGeXtVOqti4GdDXxm8J6Cbsm8al9QBxEB2A9+hDnY6d7IUomvKZoY88nB9GalocHnuOk8b1eAkGWraX4bXA8TEpiCEITliKfRvwddyzB2aq4n0KGpyLsEXENtom7tddRphwz9LbWeHHWQKBgFuJ/LYq+5bToyvsSMhvFyG6o6HMmCr7yB21a+HxTXlTCjwcLmhMgYmiEXE8T1ct2mhlHhhvq8K8FpCzHBS5jQXkNnpQD8iIsVhKkNNhMMNmpozJnG6P5TuNLCoA5ncdcA/FAhw5XGirdHuL84Y5129x4E6TNEnSJIjVoVEC56DpAoGBAMqetUxfzx57TlZeBegIlaWYhDczB22s6YAiCurWBKOdwhGfZfUuYt5wkrfy3zi6oH2f9kxh4mq+yk7Pc8oXktk6Z1GahTjNuhHI5ESh9cX12L2RbypJwUWWfe4EfRDOdVlaOLI3ECAi8rFpoAUaZIIKzcJF46Ve9Frm+L82eH91", 690 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDA3bAoQMUofndXMXikEU2MOJbfI1uaZbIDrxW0bEO6IOhwe/J0jWJHL2fWc2mbp2NxAH4Db1kZIcl9D0owoRf2cT5k0Y2Dah86dGz4fIedkqGryoWAnEJ2hHKGXGQf2K9OS2L8eaDLGU4CBds0m80vrn153Uiyj7zxWDYqcySM0qQjSg+mvgqpBcxKpd+xACaWNDL8qWvDsBF1D0RuO8hUiXMIKOUoFAGbqe6qWGK0COrEYQTAMydoFuSaAccP70zKQslnSOCKvsOi/iPRKGDNqWINIC/lwqXEIpMj3K+b/A+x41zR7frTgHNLbe4yHWAVNPEwTFningbB/lIyyVmDAgMBAAECggEBALxwnipmRnyvPClMY+RiJ5PGwtqYcGsly82/pwRW98GHX7Rv1lA8x/ZnghxNPbVg0k9ZvMXcaICeu4BejQ2AiKo4sU7OVGc/K+3wTXxoKBU0bJQuV0x24JVuCXvwD7/x9i8Yh0nKCOoH+mkNkcUQKWXaJi0IoXwd5u0kVCAbym1vux/9DcwtydqT4P1EoxEHCXDuRorBP8vYWCZBwRY2etmdAEbHsVpVlNlXWfbGCNMf5e8AecOZre4No8UfTOZkM7YKgjryde3YCmY2zDQI9jExGD2L5nptLizODD5imdpp/IQ7qg6rR3XbIK6CDiKiePEFQibD8XWiz7XVD6JBRokCgYEA0jEAxZseHUyobh1ERHezs2vC2zbiTOfnOpFxhwtNt67dUQZDssTxXF+BymUL8yKi1bnheOTuyASxrgZ7BPdiFvJfhlelSxtxtt1RamY58E179uiel2NPRsR3SL2AsGg+jP+QjJpsJHvYIliXP38G7NVaqaSMFgXfXir7Ty7W0r0CgYEA6uYQWfjmaB66xPrL/oCBaJ+UWM/Zdfw4IETVnRVOxVqGE7AKqC+31fZQ5kIXnNcJNLJ0OJlhGH5vZYp/r4z6qly9BUVolCJcW2YLEOOnChOvKGwlDSXrdGty2f34RXdABwsf/pBHsdpJq70+SE01tTB/8P2NTnRafy9GL/FnwT8CgYEAjJ4D6i8wImHafHBP7441Rl9daNJ66wBqDSCoVrQVNkFiBoauW7at0iKC7ihTqkENtvY4BW0C4gVh6Q6k1lm54agch/+ysWCW3sOJaCkjscPknvZYwubJboqZUqyUn2/eCO4ggi/9ERtZKQEjjnMo6uCBWuSeY01iddlDb2HijfECgYBYQCM4ikiWKaVlyAvIDCOSWRH04/IBX8b+aJ4QrCayAraIwwTd9z+MBUSTnZUdebSdtcXwVb+i4i2b6pLaM48hXkItrswBi39DX20c5UqmgIq4Fxk8fVienpfByqbyAkFt5AIbM72b1jUDbs/tfgSFlDkdI0VpilFNo0ctT/b5JQKBgAxPGtVGzhSQUZWPXjhiBT7MM/1EiLBYhGVrymzd9dmBxj+UyifnRXfIQbOQm3EfI5Z8ZpyS6eqWdi9NTeZi8rg0WleMb/VbOMT3xvTO34vDXvwrQKhFMimX1tY7aKy1udnE2ON2/alq2zWo3zPZfYH1KFdDtGD08GW2M4OO1caa", 691 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGj2wLnDIHnP6wjJ+WmIhp7NGAaKWwfxBWfdMFR+Y0ilkK5ld5igT45UHAmzN3v4HcwHGGpPITD9caDYj5YaGOX+dSdGLgXWwItR0j+ivrHEJmvz8hG6z9wKEZKUUrRw7Ob72S0LOsreq98bjdiWJKHNka27slqQjGyhLQtcg6pe1CLJtnuJH4GEMLj7jJB3/Mqv3vl5CQZ+Js0bXfgw5TF/x/Bzq/8qsxQ1vnmYHJsR0eLPEuDJOvoFPiJZytI09S7qBEJL5PDeVSfjQi3o71sqOzZlEL0b0Ny48rfo/mwJAdkmfcnydRDxeGUEqpAWICCOdUL0+W3/fCffaRZsk1AgMBAAECggEAUuyO6QJgeoF8dGsmMxSc0/ANRp1tpRpLznNZ77ipUYP9z+mG2sFjdjb4kOHASuB18aWFRAAbAQ76fGzuqYe2muk+iFcG/EDH35MUCnRuZxA0QwjX6pHOW2NZZFKyCnLwohJUj74Na65ufMk4tXysydrmaKsfq4i+m5bE6NkiOCtbXsjUGVdJKzkT6X1gEyEPEHgrgVZz9OpRY5nwjZBMcFI6EibFnWdehcuCQLESIX9ll/QzGvTJ1p8xeVJs2ktLWKQ38RewwucNYVLVJmxS1LCPP8x+yHVkOxD66eIncY26sjX+VbyICkaG/ZjKBuoOekOq/T+b6q5ESxWUNfcu+QKBgQDmt3WVBrW6EXKtN1MrVyBoSfn9WHyf8Rfb84t5iNtaWGSyPZK/arUw1DRbI0TdPjct//wMWoUU2/uqcPSzudTaPena3oxjKReXso1hcynHqboCaXJMxWSqDQLumbrVY05C1WFSyhRY0iQS5fIrNzD4+6rmeC2Aj5DKNW5Atda8dwKBgQDcUdhQfjL9SmzzIeAqJUBIfSSI2pSTsZrnrvMtSMkYJbzwYrUdhIVxaS4hXuQYmGgwonLctyvJxVxEMnf+U0nqPgJHE9nGQb5BbK6/LqxBWRJQlc+W6EYodIwvtE5B4JNkPE5757u+xlDdHe2zGUGXSIf4IjBNbSpCu6RcFsGOswKBgEnr4gqbmcJCMOH65fTu930yppxbq6J7Vs+sWrXX+aAazjilrc0S3XcFprjEth3E/10HtbQnlJg4W4wioOSs19wNFk6AG67xzZNXLCFbCrnkUarQKkUawcQSYywbqVcReFPFlmc2RAqpWdGMR2k9R72etQUe4EVeul9veyHUoTbFAoGBAKj3J9NLhaVVb8ri3vzThsJRHzTJlYrTeb5XIO5I1NhtEMK2oLobiQ+aH6O+F2Z5c+Zgn4CABdf/QSyYHAhzLcu0dKC4K5rtjpC0XiwHClovimk9C3BrgGrEP0LSn/XL2p3T1kkWRpkflKKPsl1ZcEEqggSdi7fFkdSN/ZYWaakbAoGBALWVGpA/vXmaZEV/hTDdtDnIHj6RXfKHCsfnyI7AdjUX4gokzdcEvFsEIoI+nnXR/PIAvwqvQw4wiUqQnp2VB8r73YZvW/0npnsidQw3ZjqnyvZ9X8y80nYs7DjSlaG0A8huy2TUdFnJyCMWby30g82kf0b/lhotJg4d3fIDou51", 692 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6q61hiC7OhlMz7JNnLiL/RwOaFC8955GDvwSMH9Zw3oguWH9nLqkmlJ98cnqRG9ZC0qVo6Gagl7gv6yOHDwD4xZI8JoV2ZfNdDzq4QzoBIzMtRsbSS4IvrF3JP+kDH1tim+CbRMBxiFJgLgS6yeeQlLNvBW+CIYzmeCimZ6CWCr91rZPIprUIdjvhxrM9EQU072Pmzn2gpGM6K5gAReN+LtP+VSBC61x7GQJxBaJNtk11PXkgG99EdFi9vvgEBbM9bdcawvf8jxvjgsgdaDx/1cypDdnaL8eistmyv1YI67bKvrSPCEh55b90hl3o3vW4W5G4gcABoyORON96Y+i9AgMBAAECggEBAKp+tyNH0QiMo13fjFpHR2vFnsKSAPwXj063nx2kzqXUeqlp5yOE+LXmNSzjGpOCy1XJM474BRRUvsP1jkODLq4JNiF+RZP4Vij/CfDWZho33jxSUrIsiUGluxtfJiHV+A++s4zdZK/NhP+XyHYah0gEqUaTvl8q6Zhu0yH5sDCZHDLxDBpgiT5qD3lli8/o2xzzBdaibZdjQyHi9v5Yi3+ysly1tmfmqnkXSsevAubwJu504WxvDUSo7hPpG4a8Xb8ODqL738GIF2UY/olCcGkWqTQEr2pOqG9XbMmlUWnxG62GCfK6KtGfIzCyBBkGO2PZa9aPhVnv2bkYxI4PkLkCgYEAzAp7xH88UbSX31suDRa4jZwgtzhJLeyc3YxO5C4XyWZ89oWrA30V1KvfVwFRavYRJW07a+r0moba+0E1Nj5yZVXPOVu0bWd9ZyMbdH2L6MRZoJWU5bUOwyruulRCkqASZbWo4G05NOVesOyY1bhZGE7RyUW0vOo8tSyyRQ8nUGMCgYEA6jTQbDry4QkUP9tDhvc8+LsobIF1mPLEJui+mT98+9IGar6oeVDKekmNDO0Dx2+miLfjMNhCb5qUc8g036ZsekHt2WuQKunADua0coB00CebMdr6AQFf7QOQ/RuA+/gPJ5G0GzWB3YOQ5gE88tTCO/jBfmikVOZvLtgXUGjo3F8CgYEAl2poMoehQZjc41mMsRXdWukztgPE+pmORzKqENbLvB+cOG01XV9j5fCtyqklvFRioP2QjSNM5aeRtcbMMDbjOaQWJaCSImYcP39kDmxkeRXM1UhruJNGIzsm8Ys55Al53ZSTgAhN3Z0hSfYp7N/i7hD/yXc7Cr5g0qoamPkH2bUCgYApf0oeoyM9tDoeRl9knpHzEFZNQ3LusrUGn96FkLY4eDIi371CIYp+uGGBlM1CnQnI16wtj2PWGnGLQkH8DqTR1LSr/V8B+4DIIyB92TzZVOsunjoFy5SPjj42WpU0D/O/cxWSbJyh/xnBZx7Bd+kibyT5nNjhIiM5DZiz6qK3yQKBgAOO/MFKHKpKOXrtafbqCyculG/ope2u4eBveHKO6ByWcUSbuD9ebtr7Lu5AC5tKUJLkSyRx4EHk71bqP1yOITj8z9wQWdVyLxtVtyj9SUkUNvGwIj+F7NJ5VgHzWVZtvYWDCzrfxkEhKk3DRIIVjqmEohJcaOZoZ2Q/f8sjlId6", 693 "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1NzommDoutE+FVAbgovPb5ioRRS1k93hhH5Mpe4KfAQb1k0aGA/TjrFr2HcRbOtldo6Fe+RRCAm5Go+sBx829zyMEdXbGtR4Pym78xYoRpsCwD+2AK/edQLjsdDf9zXZod9ig/Pe59awYaeuSFyK/w9q94ncuiE7m+MKfXJnTS/qiwwkxWIRm9lBprPIT0DwXCtoh7FdpsOmjLu2QdGADV+9KSDgV5IbVcxwjPY03vHJS4UAIP5eS46TtSrNF3hyM9Q8vGIPAixOVyAY53cRQUxZWU/FIaNjaEgpreUQfK1pgr0gxh1K7IKwmyF3f/JgL0urFljYp2UonzRU5XKHJAgMBAAECggEBAKVT2HLDqTlY+b/LNGcXY+H4b+LHuS2HdUUuuGU9MKN+HWpIziuQSoi4g1hNOgp9ezgqBByQpAHBE/jQraQ3NKZ55xm3TQDm1qFTb8SfOGL4Po2iSm0IL+VA2jWnpjmgjOmshXACusPmtfakE+55uxM3TUa16UQDyfCBfZZEtnaFLTYzJ7KmD2GPot8SCxJBqNmW7AL8pMSIxMC3cRxUbK4R3+KIisXUuB50jZH3zGHxi34e2jA6gDeFmzgHCDJRidHMsCTHTaATzlvVz9YwwNqPQaYY7OFouZXwFxVAxIg/1zVvLc3zx1gWt+UDFeI7h6Eq0h5DZPdUiR4mrhAKd70CgYEAw6WKbPgjzhJI9XVmnu0aMHHH4MK8pbIq4kddChw24yZv1e9qnNTHw3YK17X9Fqog9CU1OX3M/vddfQbc34SorBmtmGYgOfDSuXTct52Ppyl4CRwndYQc0A88Hw+klluTEPY3+NRV6YSzv8vkNMasVuOh0YI1xzbpc+Bb5LL3kwMCgYEA7R4PLYYmtzKAY2YTQOXGBh3xd6UEHgks30W+QzDxvOv75svZt6yDgiwJzXtyrQzbNaH6yca5nfjkqyhnHwpguJ6DK7+S/RnZfVib5MqRwiU7g8l3neKhIXs6xZxfORunDU9T5ntbyNaGv/TJ2cXNw+9VskhBaHfEN/kmaBNNuEMCgYARLuzlfTXH15tI07Lbqn9uWc/wUao381oI3bOyO6Amey2/YHPAqn+RD0EMiRNddjvGta3jCsWCbz9qx7uGdiRKWUcB55ZVAG3BlB3+knwXdnDwe+SLUbsmGvBw2fLesdRM3RM1a5DQHbOb2NCGQhzI1N1VhVYr1QrT/pSTlZRg+QKBgCE05nc/pEhfoC9LakLaauMManaQ+4ShUFFsWPrb7d7BRaPKxJC+biRauny2XxbxB/n410BOvkvrQUre+6ITN/xi5ofH6nPbnOO69woRfFwuDqmkG0ZXKK2hrldiUMuUnc51X5CVkgMMWA6l32bKFsjryZqQF+jjbO1RzRkiKu41AoGAHQer1NyajHEpEfempx8YTsAnOn+Hi33cXAaQoTkS41lX2YK0cBkD18yhubczZcKnMW+GRKZRYXMm0NfwiuIo5oIYWeO6K+rXF+SKptC5mnw/3FhDVnghDAmEqOcRSWnFXARk1WEbFtwG5phDeFrWXsqPzGAjoZ8bhLvKRsrG4OM=", 694 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBdNw4C8zUmLDkV+mTSqevRzBs28V7/nND5Onu26Yr9mdPfujtfQVQRevE2L52SGZ4nSCxqI34lAY1R7C+lKQ8gBcq+L3TxpJ8IaOztsaUkIkK4O4vl3qbuFmc/2u318lzvQYSU+kbSNz19fCXPtOWw9vZ5xq2YbTljiM/B0L6g3gw0K/3JDMS8JUzOXvoQlozrTaQgcLUIhKfSsMWZh32tI3tc+U0nDUXo9ukn8FZD6lccrDc4TA1MRMBQ1iJUadlT4HtrttkL1/r9o9sm5W3xCaD5ScO9bVjyCZ8efFpYbZ/lMMG8IeZxi25whk8tAPi2sCjMLivKqWYJZA0pu3TAgMBAAECggEAZMYWLU/gTGKZyukMsIB0JzcjP6GgFv4uVxC414ct4brCiEOo3IWCrhUuQuVRGdaPIodfT4xpIDMjpL+Kj0xo3WcwKl9WqynGhskTOHueqCc+bB9NlBcJdHKso77eAu9ybkrqDcQOKvtitvF9eZvtppyyOqlLXfQ5wlavf5atykamHP6JTUdXDkF7EOvoBxN0a2JsUObxr83hWo6KVuvltV/BNvjFv0wQc2jJ3V/y9wvfLwhfjTWo2PMFoGS1M3cn4JkTn2MDDRSd/A1BTOdE6FAZDeOVKV7AmLF5BsIy4QOH86Aj7qenPGKT6bJnR7SHRhn0WLxNXrdCqtZM9WVZsQKBgQD9M8EMgAumo/ydVTj87UxvMCv7jMGaD+sCT3DCqVW4gv1KMi5O7MZnOFG7chdh/X0pgb+rh7zYGUCvL2lOMN4/wb9yGZm2JvFEFh2P9ZahqiyWjYcIo1mOPcQVu5XOCusWDISA084sHOLGFvhkuDi1giQljz5eTccCcFgHlP02KQKBgQDDmBm43jixdx14r29T97PZq5cwap3ZGBWcT3ZhqK9T400nHF+QmJVLVoTrl6eh21CVafdh8gHAgn4zuiNdxJKaxlehzaEAX+luq0htQMTiqLvWrPzQieP9wnB8Cz9ECC/oAFyjALF0+c+7vWf3b4JTPWChEl35caJgZLFoSpRrmwKBgQDGE+ew5La4nU7wsgvL6cPCs9ekiR+na0541zaqQhhaKLcHhSwu+BHaC/f8gKuEL+7rOqJ8CMsV7uNoaNmjnp0vGV2wYBCcq+hQUFC+HuzA+cS53mvFuSxFF1K/gakWr/nqnM5HjeqbHdnWB4A4ItnSPMYUT/QFiCjoYoSrIcXYyQKBgFveTwaT6dEA/6i1zfaEe8cbX1HwYd+b/lqCwDmyf1dJhe1+2CwUXtsZ8iit/KB7YGgtc3Jftw7yu9AT95SNRcbIrlRjPuHsKro+XTBjoZZMZp24dq6Edb+02hyJM9gCeG3h7aDqLG+i/j1SA0km6PGr/HzrIZSOGRRpdyJjFT9NAoGBAKfW5NSxvd5np2UrzjqU+J/BsrQ2bzbSyMrRnQTjJSkifEohPRvP4Qy0o9Pkvw2DOCVdoY67+BhDCEC6uvr4RbWi9MJr832tJn3CdT/j9+CZzUFezT8ldnAwCJMBoRTX46tg5rw5u67af0O/x0L00Daqhsu7nQE8Kvx7pFAn6fFO", 695 "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCq1BCPAUsc97P7u4X0Bfu68sUebdLI0ijOGFWYaHEcizTF2BGdkqbOZmQV2sW5d10FMCCVTgLa7d3DXSMk7VpYgVAXxsaREdkbs93bn9eZZYFE+Y4nE0t5YGqmPQb7bNMyCcBXvaEAtIMVjb9AOzFS2F6crDRKumPUtTC9FvJVBDx8a7i/QcAIWeU5faEJDCF8CcatvRXvRjYgm774w/vqLj2Z3S9HQy/dZuwQlQ2nV9MhTOSBYHfWJy9+s2ZpoDHDkWQAT4p+STKWFHGLmLlFHVdBQg1ZzYqPYquj4Ilqsob73NqwzI3v4PbfSCkRKLyte/VLBG7zrkVHeAA10NIzAgMBAAECggEAJQLTH5ihJIKKTTUAvbD6LDPi/0e+DmJyEsz05pNiRlPmuCKrFl+qojdO4elHQ3qX/cLCnHaNac91Z5lrPtnp5BkIOE6JwO6EAluC6s2D0alLS51h7hdhF8gK8z9vntOiIko4kQn1swhpCidu00S/1/om7Xzly3b8oB4tlBo/oKlyrhoZr9r3VDPwJVY1Z9r1feyjNtUVblDRRLBXBGyeCqUhPgESM+huNIVl8QM7zXMs0ie2QrjWSevF6Hzcdxqf05/UwVj0tfMrWf9kTz6aUR1ZUYuzuVxEn96xmrsnvAXI9BTYpRKdZzTfL5gItxdvfF6uPrK0W9QNS9ZIk7EUgQKBgQDOzP82IsZhywEr0D4bOm6GIspk05LGEi6AVVp1YaP9ZxGGTXwIXpXPbWhoZh8o3smnVgW89kD4xIA+2AXJRS/ZSA+XCqlIzGSfekd8UfLM6o6zDiC0YGgce4xMhcHXabKrGquEp64a4hrs3JcrQCM0EqhFlpOWrX3On4JJI/QlwQKBgQDTeDQizbn/wygAn1kccSBeOx45Pc8Bkpcq8KxVYsYpwpKcz4m7hqPIcz8kOofWGFqjV2AHEIoDm5OB5DwejutKJQIJhGln/boS5fOJDhvOwSaV8Lo7ehcqGqD1tbvZfDQJWjEf6acj2owIBNU5ni0GlHo/zqyu+ibaABPH36f88wKBgA8e/io/MLJF3bgOafwjsaEtOg9VSQ4iljPcCdk7YnpM5wMi90bFY77fCRtZHD4ozCXoLFM8zlNiSt5NfV7SKEWC92Db7rTb/R+MGV4Fv/Mr03NUPR/zTKmIfyG5RgsyN1Y7hP8WI6zji4R2PLd04R4Vnyg3cmM6HFDXaPdgIaIBAoGAKOYPl0eYmImi+/PVpTWP4Amo/8MffRtf1zMy8VSoJL1345IT/ku883CunpAfY13UcdDdRqCBQM9fCPkeU36qrO1ZZoPQawdcbHlCz5gF8sfScZ9cNVKYllEOHldmnFp0Kfbil1x2Me37tTVSE9GuvZ4LwrlzFmhVCUaIjNiJwdcCgYBnR7lp+rnJpXPkvllArmrKEvhcyCbcDIEGaV8aPUsXfXoVMUaiVEybdUrL3IuLtNgiab3qNZ/knYSsuAW+0tnoaOhRCUFzK47x+uLFFKCMw4FOOOJJzVu8E/5Lu0d6FpU7MuVXMa0UUGIqfOYNGywuo3XOIfWHh3iSHUg1X6/+1A==", 696 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSIsx0TsUCeSHXDYPzViqRwB/wZhBkj5f0Mrc+Q0yogUmiTcubYQcf/xj9LOvtArJ+8/rori0j8aFX17jZqtFyDDINyhICT+i5bk1ZKPt/uH/H5oFpjtsL+bCoOF8F4AUeELExH0dO3uwl8v9fPZZ3AZEGj6UB6Ru13LON7fKHt+JT6s9jNtUIUpHUDg2GZYv9gLFGDDm9H91Yervl8yF6VWbK+7pcVyhlz5wqHR/qNUiyUXhiie+veiJc9ipCU7RriNEuehvF12d3rRIOK/wRsFAG4LxufJS8Shu8VJrOBlKzsufqjDZtnZb8SrTY0EjLJpslMf67zRDD1kEDpq4jAgMBAAECggEBAMeKxe2YMxpjHpBRRECZTTk0YN/ue5iShrAcTMeyLqRAiUS3bSXyIErw+bDIrIxXKFrHoja71x+vvw9kSSNhQxxymkFf5nQNn6geJxMIiLJC6AxSRgeP4U/g3jEPvqQck592KFzGH/e0Vji/JGMzX6NIeIfrdbx3uJmcp2CaWNkoOs7UYV5VbNDaIWYcgptQS9hJpCQ+cuMov7scXE88uKtwAl+0VVopNr/XA7vV+npsESBCt3dfnp6poA13ldfqReLdPTmDWH7Z8QrTIagrfPi5mKpxksTYyC0/quKyk4yTj8Ge5GWmsXCHtyf19NX7reeJa8MjEWonYDCdnqReDoECgYEA8R5OHNIGC6yw6ZyTuyEt2epXwUj0h2Z9d+JAT9ndRGK9xdMqJt4acjxfcEck2wjv9BuNLr5YvLc4CYiOgyqJHNt5c5Ys5rJEOgBZ2IFoaoXZNom2LEtr583T4RFXp/Id8ix85D6EZj8Hp6OvZygQFwEYQexY383hZZh5enkorUECgYEA3xr3u/SbttM86ib1RP1uuON9ZURfzpmrr2ubSWiRDqwift0T2HesdhWi6xDGjzGyeT5e7irf1BsBKUq2dp/wFX6+15A6eV12C7PvC4N8u3NJwGBdvCmufh5wZ19rerelaB7+vG9c+Nbw9h1BbDi8MlGs06oVSawvwUzp2oVKLmMCgYEAq1RFXOU/tnv3GYhQ0N86nWWPBaC5YJzK+qyh1huQxk8DWdY6VXPshs+vYTCsV5d6KZKKN3S5yR7Hir6lxT4sP30UR7WmIib5o90r+lO5xjdlqQMhl0fgXM48h+iyyHuaG8LQ274whhazccM1l683/6Cfg/hVDnJUfsRhTU1aQgECgYBrZPTZcf6+u+I3qHcqNYBl2YPUCly/+7LsJzVB2ebxlCSqwsq5yamn0fRxiMq7xSVvPXm+1b6WwEUH1mIMqiKMhk1hQJkVMMsRCRVJioqxROa8hua4G6xWI1riN8lp8hraCwl+NXEgi37ESgLjEFBvPGegH+BNbWgzeU2clcrGlwKBgHBxlFLf6AjDxjR8Z5dnZVPyvLOUjejs5nsLdOfONJ8F/MU0PoKFWdBavhbnwXwium6NvcearnhbWL758sKooZviQL6m/sKDGWMq3O8SCnX+TKTEOw+kLLFn4L3sT02WaHYg+C5iVEDdGlsXSehhI2e7hBoTulE/zbUkbA3+wlmv", 697 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6LR5HNVS8rwA6P8U9TGOwEQ1Z8bVTCfWXJ+SjzPNYaTh/YWHA9bg+0TIKbXB9yxPVETKbEBYaP953OcIXJjGFtHNi4snhOP2/F61XoGkLltSDE2tOaGQJ0gQ5uhkGjmK2jfptBcESAZ2W4UzQkV6mGej194leGLjtxdk0A9b/Rk0MPMDrurnHH818pU2XsWfEabUGFAQlU4SuZmLHPqnxMDkOXjnOQdyXweSeMtQVYgiUOy8xkY+ecAbm7f+HGuZM5uSaAg/6z7xOpvVJeACI2PVme6pGV46o5yJUO56tt/ioCmrvgun7LqDDU0VxPuiX5WuwGeNUFrHi0boz3XivAgMBAAECggEAdWgYjQ1rx6WQvisTBooS36iRQ+Ry1dAVCWLGBCouV9XbJDFURSxwKWUhaoQDicC0XAyBXloxphIbCBLrfE/AsTHQBk9AwoB/PLAAx57IP9+5WoO3ivW4CJ1hvsnGGGVYiQlWIMSdMe7E465nE6xpBNSYHe0huq5aiM/ZHr1BKy+l5T2z2k0437+3d8RhSfwlW8T7WYWK2rQZ3hPq9Cl+gDvyvcMNt2Wo9AGonwB+XtrF13tF3nqnPx8jomj4pbmFXMzKR5RsgWNX2Fec064e53OQzkYhqQ6mByUPA//UxfOO1BtNwhFQUjNEZCYMKWcD3EoR17dcosX/GlHt+MZGuQKBgQDWBdDKqV3zZSjeUJwnkd3ykdNdVggqJiNfLww3owUG1E/VUHZuvYzsJbyWp0g+rLESqa+sPp8cKP93q1ve4Dw9Dqp4ejR8hqYUEzq2Adrcgb30WDj5IZRnku34CGsq/wUP9IOyA7chZYONzllY07m/W9ZZcSwG6ziXFeyPj4XzbQKBgQDesR4jMSEys2b5PA4MO+rQYgbKj+lVzHn4uYX0ghhuoYwZYEZ0yJKyDztbgD2x7/DP8bYAZTuksqRk4Ss/bS6iRDZlGQQaXVNeEJMiIMbLCDxx69I312nYHgZ0/ETyk/5eOdJkObshkTrFA0UO13c9t4jRQfNdjTepQj56mTcvCwKBgQCQXaXkPnCoULFLnNZofqVXDXSkvfaN7+HmP8ce9HDclXQwcLEiq+uWEzJt8PLzi+t5qkpchnUvOpxwbX9wDJO1n+HvmIc1BGKcogf1Y7TtDvtCCgyMSFFhuCObLpqTiygwBgCboJP0DBS8H9f26gKeiOVCues304z9pQVIJUj21QKBgBsUDGcZFUFWAUJzI/4m1wGpucutviC5sWcmH/zASPpC2IdJZqfSr8vJAF269UWKuIyAhrH7nUoEkurVWm3m99GxW6/lX9NY38dDWrC+rY2Indj4ZOJ3Zh5qYDyfZD7e8gJBI60eO/vz7eKA6EfKuWwewhs32sDYaBlDvdcohEZLAoGBAIoWjKNJg02dKQUU4df1BjhvEw5pSEh4hGDBR12cD52ibqGPLF36TBwVnNL284BXipjBWejzvVnCUAzflym4UgMUidhJxpVrVJSx0Tdclr0+70Lz6emtNA4e+A9ttJLwuiZrmct7G9FWJ6GgBa/1z7a+/qRLM4SMxgbMufQcIl+r", 698 } 699 700 if diff := len(accountsSorted) - len(preserializedKeys); diff > 0 { 701 keyStrings := make([]string, diff) 702 for i := 0; i < diff; i++ { 703 priv, _ := rsa.GenerateKey(rand.Reader, 2048) 704 key, _ := x509.MarshalPKCS8PrivateKey(priv) 705 keyStrings = append(keyStrings, base64.StdEncoding.EncodeToString(key)) 706 } 707 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)) 708 } 709 710 for i, v := range accountsSorted { 711 premadeBytes, err := base64.StdEncoding.DecodeString(preserializedKeys[i]) 712 if err != nil { 713 panic(err) 714 } 715 key, err := x509.ParsePKCS8PrivateKey(premadeBytes) 716 if err != nil { 717 panic(err) 718 } 719 priv, ok := key.(*rsa.PrivateKey) 720 if !ok { 721 panic(fmt.Sprintf("generated key at index %d is of incorrect type", i)) 722 } 723 v.PrivateKey = priv 724 v.PublicKey = &priv.PublicKey 725 } 726 727 return accounts 728 } 729 730 func NewTestTombstones() map[string]*gtsmodel.Tombstone { 731 return map[string]*gtsmodel.Tombstone{ 732 "https://somewhere.mysterious/users/rest_in_piss#main-key": { 733 ID: "01GHBTVE9HQPPBDH2W5VH2DGN4", 734 CreatedAt: TimeMustParse("2021-11-09T19:33:45Z"), 735 UpdatedAt: TimeMustParse("2021-11-09T19:33:45Z"), 736 Domain: "somewhere.mysterious", 737 URI: "https://somewhere.mysterious/users/rest_in_piss#main-key", 738 }, 739 } 740 } 741 742 // NewTestAttachments returns a map of attachments keyed according to which account 743 // and status they belong to, and which attachment number of that status they are. 744 func NewTestAttachments() map[string]*gtsmodel.MediaAttachment { 745 return map[string]*gtsmodel.MediaAttachment{ 746 "admin_account_status_1_attachment_1": { 747 ID: "01F8MH6NEM8D7527KZAECTCR76", 748 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", 749 URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg", 750 RemoteURL: "", 751 CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 752 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 753 Type: gtsmodel.FileTypeImage, 754 FileMeta: gtsmodel.FileMeta{ 755 Original: gtsmodel.Original{ 756 Width: 1200, 757 Height: 630, 758 Size: 756000, 759 Aspect: 1.9047619047619047, 760 }, 761 Small: gtsmodel.Small{ 762 Width: 256, 763 Height: 134, 764 Size: 34304, 765 Aspect: 1.9104477611940298, 766 }, 767 }, 768 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 769 Description: "Black and white image of some 50's style text saying: Welcome On Board", 770 ScheduledStatusID: "", 771 Blurhash: "LNJRdVM{00Rj%Mayt7j[4nWBofRj", 772 Processing: 2, 773 File: gtsmodel.File{ 774 Path: "01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg", 775 ContentType: "image/jpeg", 776 FileSize: 62529, 777 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 778 }, 779 Thumbnail: gtsmodel.Thumbnail{ 780 Path: "01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg", 781 ContentType: "image/jpeg", 782 FileSize: 6872, 783 UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), 784 URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpg", 785 RemoteURL: "", 786 }, 787 Avatar: FalseBool(), 788 Header: FalseBool(), 789 Cached: TrueBool(), 790 }, 791 "local_account_1_status_4_attachment_1": { 792 ID: "01F8MH7TDVANYKWVE8VVKFPJTJ", 793 StatusID: "01F8MH82FYRXD2RC6108DAJ5HB", 794 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH7TDVANYKWVE8VVKFPJTJ.gif", 795 RemoteURL: "", 796 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 797 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 798 Type: gtsmodel.FileTypeImage, 799 FileMeta: gtsmodel.FileMeta{ 800 Original: gtsmodel.Original{ 801 Width: 400, 802 Height: 280, 803 Size: 756000, 804 Aspect: 1.4285714285714286, 805 }, 806 Small: gtsmodel.Small{ 807 Width: 256, 808 Height: 179, 809 Size: 45824, 810 Aspect: 1.4301675977653632, 811 }, 812 Focus: gtsmodel.Focus{ 813 X: 0, 814 Y: 0, 815 }, 816 }, 817 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 818 Description: "90's Trent Reznor turning to the camera", 819 ScheduledStatusID: "", 820 Blurhash: "LEDara58O=t5EMSOENEN9]}?aK%0", 821 Processing: 2, 822 File: gtsmodel.File{ 823 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH7TDVANYKWVE8VVKFPJTJ.gif", 824 ContentType: "image/gif", 825 FileSize: 1109138, 826 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 827 }, 828 Thumbnail: gtsmodel.Thumbnail{ 829 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpg", 830 ContentType: "image/jpeg", 831 FileSize: 8803, 832 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 833 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpg", 834 RemoteURL: "", 835 }, 836 Avatar: FalseBool(), 837 Header: FalseBool(), 838 Cached: TrueBool(), 839 }, 840 "local_account_1_status_4_attachment_2": { 841 ID: "01CDR64G398ADCHXK08WWTHEZ5", 842 StatusID: "01F8MH82FYRXD2RC6108DAJ5HB", 843 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.mp4", 844 RemoteURL: "", 845 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 846 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 847 Type: gtsmodel.FileTypeVideo, 848 FileMeta: gtsmodel.FileMeta{ 849 Original: gtsmodel.Original{ 850 Width: 720, 851 Height: 404, 852 Size: 290880, 853 Aspect: 1.78217821782178, 854 Duration: Float32Ptr(15.033334), 855 Framerate: Float32Ptr(30.0), 856 Bitrate: Uint64Ptr(1206522), 857 }, 858 Small: gtsmodel.Small{ 859 Width: 720, 860 Height: 404, 861 Size: 290880, 862 Aspect: 1.78217821782178, 863 }, 864 Focus: gtsmodel.Focus{ 865 X: 0, 866 Y: 0, 867 }, 868 }, 869 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 870 Description: "A cow adorably licking another cow!", 871 ScheduledStatusID: "", 872 Blurhash: "", 873 Processing: 2, 874 File: gtsmodel.File{ 875 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.gif", 876 ContentType: "video/mp4", 877 FileSize: 2273532, 878 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 879 }, 880 Thumbnail: gtsmodel.Thumbnail{ 881 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.jpg", 882 ContentType: "image/jpeg", 883 FileSize: 5272, 884 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 885 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01CDR64G398ADCHXK08WWTHEZ5.jpg", 886 RemoteURL: "", 887 }, 888 Avatar: FalseBool(), 889 Header: FalseBool(), 890 Cached: TrueBool(), 891 }, 892 "local_account_1_unattached_1": { 893 ID: "01F8MH8RMYQ6MSNY3JM2XT1CQ5", 894 StatusID: "", // this attachment isn't connected to a status YET 895 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", 896 RemoteURL: "", 897 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 898 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 899 Type: gtsmodel.FileTypeImage, 900 FileMeta: gtsmodel.FileMeta{ 901 Original: gtsmodel.Original{ 902 Width: 800, 903 Height: 450, 904 Size: 360000, 905 Aspect: 1.7777777777777777, 906 }, 907 Small: gtsmodel.Small{ 908 Width: 256, 909 Height: 144, 910 Size: 36864, 911 Aspect: 1.7777777777777777, 912 }, 913 Focus: gtsmodel.Focus{ 914 X: 0, 915 Y: 0, 916 }, 917 }, 918 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 919 Description: "the oh you meme", 920 ScheduledStatusID: "", 921 Blurhash: "LSAd]9ogDge-R:M|j=xWIto0xXWX", 922 Processing: 2, 923 File: gtsmodel.File{ 924 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", 925 ContentType: "image/jpeg", 926 FileSize: 27759, 927 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 928 }, 929 Thumbnail: gtsmodel.Thumbnail{ 930 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", 931 ContentType: "image/jpeg", 932 FileSize: 6177, 933 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 934 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg", 935 RemoteURL: "", 936 }, 937 Avatar: FalseBool(), 938 Header: FalseBool(), 939 Cached: TrueBool(), 940 }, 941 "local_account_1_avatar": { 942 ID: "01F8MH58A357CV5K7R7TJMSH6S", 943 StatusID: "", // this attachment isn't connected to a status 944 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg", 945 RemoteURL: "", 946 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 947 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 948 Type: gtsmodel.FileTypeImage, 949 FileMeta: gtsmodel.FileMeta{ 950 Original: gtsmodel.Original{ 951 Width: 1092, 952 Height: 1800, 953 Size: 1965600, 954 Aspect: 0.6066666666666667, 955 }, 956 Small: gtsmodel.Small{ 957 Width: 155, 958 Height: 256, 959 Size: 39680, 960 Aspect: 0.60546875, 961 }, 962 Focus: gtsmodel.Focus{ 963 X: 0, 964 Y: 0, 965 }, 966 }, 967 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 968 Description: "a green goblin looking nasty", 969 ScheduledStatusID: "", 970 Blurhash: "LKK9MT,p|YSNDkJ-5rsmvnwcOoe:", 971 Processing: 2, 972 File: gtsmodel.File{ 973 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg", 974 ContentType: "image/jpeg", 975 FileSize: 457680, 976 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 977 }, 978 Thumbnail: gtsmodel.Thumbnail{ 979 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg", 980 ContentType: "image/jpeg", 981 FileSize: 15374, 982 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 983 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpg", 984 RemoteURL: "", 985 }, 986 Avatar: TrueBool(), 987 Header: FalseBool(), 988 Cached: TrueBool(), 989 }, 990 "local_account_1_header": { 991 ID: "01PFPMWK2FF0D9WMHEJHR07C3Q", 992 StatusID: "", 993 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", 994 RemoteURL: "", 995 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 996 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 997 Type: gtsmodel.FileTypeImage, 998 FileMeta: gtsmodel.FileMeta{ 999 Original: gtsmodel.Original{ 1000 Width: 1018, 1001 Height: 764, 1002 Size: 777752, 1003 Aspect: 1.3324607329842932, 1004 }, 1005 Small: gtsmodel.Small{ 1006 Width: 256, 1007 Height: 192, 1008 Size: 49152, 1009 Aspect: 1.3333333333333333, 1010 }, 1011 Focus: gtsmodel.Focus{ 1012 X: 0, 1013 Y: 0, 1014 }, 1015 }, 1016 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1017 Description: "A very old-school screenshot of the original team fortress mod for quake ", 1018 ScheduledStatusID: "", 1019 Blurhash: "L26j{^WCs+R-N}jsxWj@4;WWxDoK", 1020 Processing: 2, 1021 File: gtsmodel.File{ 1022 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", 1023 ContentType: "image/jpeg", 1024 FileSize: 517226, 1025 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1026 }, 1027 Thumbnail: gtsmodel.Thumbnail{ 1028 Path: "01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", 1029 ContentType: "image/jpeg", 1030 FileSize: 42308, 1031 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1032 URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg", 1033 RemoteURL: "", 1034 }, 1035 Avatar: FalseBool(), 1036 Header: TrueBool(), 1037 Cached: TrueBool(), 1038 }, 1039 "remote_account_1_status_1_attachment_1": { 1040 ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY0", 1041 StatusID: "01FVW7JHQFSFK166WWKR8CBA6M", 1042 URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", 1043 RemoteURL: "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg", 1044 CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1045 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1046 Type: gtsmodel.FileTypeImage, 1047 FileMeta: gtsmodel.FileMeta{ 1048 Original: gtsmodel.Original{ 1049 Width: 472, 1050 Height: 291, 1051 Size: 137352, 1052 Aspect: 1.6219931271477663, 1053 }, 1054 Small: gtsmodel.Small{ 1055 Width: 472, 1056 Height: 291, 1057 Size: 137352, 1058 Aspect: 1.6219931271477663, 1059 }, 1060 Focus: gtsmodel.Focus{ 1061 X: 0, 1062 Y: 0, 1063 }, 1064 }, 1065 AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 1066 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", 1067 ScheduledStatusID: "", 1068 Blurhash: "LARysgM_IU_3~pD%M_Rj_39FIAt6", 1069 Processing: 2, 1070 File: gtsmodel.File{ 1071 Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", 1072 ContentType: "image/jpeg", 1073 FileSize: 19310, 1074 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1075 }, 1076 Thumbnail: gtsmodel.Thumbnail{ 1077 Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", 1078 ContentType: "image/jpeg", 1079 FileSize: 19312, 1080 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1081 URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg", 1082 RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", 1083 }, 1084 Avatar: FalseBool(), 1085 Header: FalseBool(), 1086 Cached: TrueBool(), 1087 }, 1088 "remote_account_3_header": { 1089 ID: "01PFPMWK2FF0D9WMHEJHR07C3R", 1090 StatusID: "", 1091 URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", 1092 RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", 1093 CreatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1094 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1095 Type: gtsmodel.FileTypeImage, 1096 FileMeta: gtsmodel.FileMeta{ 1097 Original: gtsmodel.Original{ 1098 Width: 472, 1099 Height: 291, 1100 Size: 137352, 1101 Aspect: 1.6219931271477663, 1102 }, 1103 Small: gtsmodel.Small{ 1104 Width: 472, 1105 Height: 291, 1106 Size: 137352, 1107 Aspect: 1.6219931271477663, 1108 }, 1109 Focus: gtsmodel.Focus{ 1110 X: 0, 1111 Y: 0, 1112 }, 1113 }, 1114 AccountID: "062G5WYKY35KKD12EMSM3F8PJ8", 1115 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", 1116 ScheduledStatusID: "", 1117 Blurhash: "LARysgM_IU_3~pD%M_Rj_39FIAt6", 1118 Processing: 2, 1119 File: gtsmodel.File{ 1120 Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", 1121 ContentType: "image/jpeg", 1122 FileSize: 19310, 1123 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1124 }, 1125 Thumbnail: gtsmodel.Thumbnail{ 1126 Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", 1127 ContentType: "image/jpeg", 1128 FileSize: 20395, 1129 UpdatedAt: TimeMustParse("2022-06-09T13:12:00Z"), 1130 URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpg", 1131 RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpg", 1132 }, 1133 Avatar: FalseBool(), 1134 Header: TrueBool(), 1135 Cached: TrueBool(), 1136 }, 1137 } 1138 } 1139 1140 // NewTestEmojis returns a map of gts emojis, keyed by the emoji shortcode 1141 func NewTestEmojis() map[string]*gtsmodel.Emoji { 1142 return map[string]*gtsmodel.Emoji{ 1143 "rainbow": { 1144 ID: "01F8MH9H8E4VG3KDYJR9EGPXCQ", 1145 Shortcode: "rainbow", 1146 Domain: "", 1147 CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1148 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1149 ImageRemoteURL: "", 1150 ImageStaticRemoteURL: "", 1151 ImageURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 1152 ImagePath: "/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 1153 ImageStaticURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 1154 ImageStaticPath: "01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 1155 ImageContentType: "image/png", 1156 ImageStaticContentType: "image/png", 1157 ImageFileSize: 36702, 1158 ImageStaticFileSize: 10413, 1159 ImageUpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1160 Disabled: FalseBool(), 1161 URI: "http://localhost:8080/emoji/01F8MH9H8E4VG3KDYJR9EGPXCQ", 1162 VisibleInPicker: TrueBool(), 1163 CategoryID: "01GGQ8V4993XK67B2JB396YFB7", 1164 }, 1165 "yell": { 1166 ID: "01GD5KP5CQEE1R3X43Y1EHS2CW", 1167 Shortcode: "yell", 1168 Domain: "fossbros-anonymous.io", 1169 CreatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), 1170 UpdatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), 1171 ImageRemoteURL: "http://fossbros-anonymous.io/emoji/yell.gif", 1172 ImageStaticRemoteURL: "", 1173 ImageURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01GD5KP5CQEE1R3X43Y1EHS2CW.png", 1174 ImagePath: "01AY6P665V14JJR0AFVRT7311Y/emoji/original/01GD5KP5CQEE1R3X43Y1EHS2CW.png", 1175 ImageStaticURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01GD5KP5CQEE1R3X43Y1EHS2CW.png", 1176 ImageStaticPath: "01AY6P665V14JJR0AFVRT7311Y/emoji/static/01GD5KP5CQEE1R3X43Y1EHS2CW.png", 1177 ImageContentType: "image/png", 1178 ImageStaticContentType: "image/png", 1179 ImageFileSize: 10889, 1180 ImageStaticFileSize: 10808, 1181 ImageUpdatedAt: TimeMustParse("2020-03-18T13:12:00+01:00"), 1182 Disabled: FalseBool(), 1183 URI: "http://fossbros-anonymous.io/emoji/01GD5KP5CQEE1R3X43Y1EHS2CW", 1184 VisibleInPicker: FalseBool(), 1185 CategoryID: "", 1186 }, 1187 } 1188 } 1189 1190 func NewTestEmojiCategories() map[string]*gtsmodel.EmojiCategory { 1191 return map[string]*gtsmodel.EmojiCategory{ 1192 "reactions": { 1193 ID: "01GGQ8V4993XK67B2JB396YFB7", 1194 Name: "reactions", 1195 CreatedAt: TimeMustParse("2020-03-18T11:40:55+02:00"), 1196 UpdatedAt: TimeMustParse("2020-03-19T12:35:12+02:00"), 1197 }, 1198 "cute stuff": { 1199 ID: "01GGQ989PTT9PMRN4FZ1WWK2B9", 1200 Name: "cute stuff", 1201 CreatedAt: TimeMustParse("2020-03-20T11:40:55+02:00"), 1202 UpdatedAt: TimeMustParse("2020-03-21T12:35:12+02:00"), 1203 }, 1204 } 1205 } 1206 1207 func NewTestStatusToEmojis() map[string]*gtsmodel.StatusToEmoji { 1208 return map[string]*gtsmodel.StatusToEmoji{ 1209 "admin_account_status_1_rainbow": { 1210 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", 1211 EmojiID: "01F8MH9H8E4VG3KDYJR9EGPXCQ", 1212 }, 1213 } 1214 } 1215 1216 func NewTestInstances() map[string]*gtsmodel.Instance { 1217 return map[string]*gtsmodel.Instance{ 1218 "localhost:8080": { 1219 ID: "01G774F5TSHJ2ZSF7XRC5EMT6K", 1220 CreatedAt: TimeMustParse("2020-01-20T13:12:00+02:00"), 1221 UpdatedAt: TimeMustParse("2020-01-20T13:12:00+02:00"), 1222 Domain: "localhost:8080", 1223 URI: "http://localhost:8080", 1224 Title: "GoToSocial Testrig Instance", 1225 ShortDescription: "<p>This is the GoToSocial testrig. It doesn't federate or anything.</p><p>When the testrig is shut down, all data on it will be deleted.</p><p>Don't use this in production!</p>", 1226 Description: "<p>This is the GoToSocial testrig. It doesn't federate or anything.</p><p>When the testrig is shut down, all data on it will be deleted.</p><p>Don't use this in production!</p>", 1227 ContactEmail: "admin@example.org", 1228 ContactAccountUsername: "admin", 1229 ContactAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1230 }, 1231 "fossbros-anonymous.io": { 1232 ID: "01G5H6YMJQKR86QZKXXQ2S95FZ", 1233 CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1234 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1235 Domain: "fossbros-anonymous.io", 1236 URI: "http://fossbros-anonymous.io", 1237 }, 1238 "example.org": { 1239 ID: "01G5H71G52DJKVBYKXPNPNDN1G", 1240 CreatedAt: TimeMustParse("2020-05-13T15:29:12+02:00"), 1241 UpdatedAt: TimeMustParse("2020-05-13T15:29:12+02:00"), 1242 Domain: "example.org", 1243 URI: "http://example.org", 1244 }, 1245 } 1246 } 1247 1248 func NewTestDomainBlocks() map[string]*gtsmodel.DomainBlock { 1249 return map[string]*gtsmodel.DomainBlock{ 1250 "replyguys.com": { 1251 ID: "01FF22EQM7X8E3RX1XGPN7S87D", 1252 CreatedAt: TimeMustParse("2020-05-13T15:29:12+02:00"), 1253 UpdatedAt: TimeMustParse("2020-05-13T15:29:12+02:00"), 1254 Domain: "replyguys.com", 1255 CreatedByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1256 PrivateComment: "i blocked this domain because they keep replying with pushy + unwarranted linux advice", 1257 PublicComment: "reply-guying to tech posts", 1258 Obfuscate: FalseBool(), 1259 }, 1260 } 1261 } 1262 1263 type filenames struct { 1264 Original string 1265 Small string 1266 Static string 1267 } 1268 1269 // newTestStoredAttachments returns a map of filenames, keyed according to which attachment they pertain to. 1270 func newTestStoredAttachments() map[string]filenames { 1271 return map[string]filenames{ 1272 "admin_account_status_1_attachment_1": { 1273 Original: "welcome-original.jpg", 1274 Small: "welcome-small.jpg", 1275 }, 1276 "local_account_1_status_4_attachment_1": { 1277 Original: "trent-original.gif", 1278 Small: "trent-small.jpg", 1279 }, 1280 "local_account_1_status_4_attachment_2": { 1281 Original: "cowlick-original.mp4", 1282 Small: "cowlick-small.jpeg", 1283 }, 1284 "local_account_1_unattached_1": { 1285 Original: "ohyou-original.jpg", 1286 Small: "ohyou-small.jpg", 1287 }, 1288 "local_account_1_avatar": { 1289 Original: "zork-original.jpg", 1290 Small: "zork-small.jpg", 1291 }, 1292 "local_account_1_header": { 1293 Original: "team-fortress-original.jpg", 1294 Small: "team-fortress-small.jpg", 1295 }, 1296 "remote_account_1_status_1_attachment_1": { 1297 Original: "thoughtsofdog-original.jpg", 1298 Small: "thoughtsofdog-small.jpg", 1299 }, 1300 } 1301 } 1302 1303 // newTestStoredEmoji returns a map of filenames, keyed according to which emoji they pertain to 1304 func newTestStoredEmoji() map[string]filenames { 1305 return map[string]filenames{ 1306 "rainbow": { 1307 Original: "rainbow-original.png", 1308 Static: "rainbow-static.png", 1309 }, 1310 "yell": { 1311 Original: "yell-original.png", 1312 Static: "yell-static.png", 1313 }, 1314 } 1315 } 1316 1317 // NewTestStatuses returns a map of statuses keyed according to which account 1318 // and status they are. 1319 func NewTestStatuses() map[string]*gtsmodel.Status { 1320 return map[string]*gtsmodel.Status{ 1321 "admin_account_status_1": { 1322 ID: "01F8MH75CBF9JFX4ZAD54N0W0R", 1323 PinnedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1324 URI: "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R", 1325 URL: "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R", 1326 Content: "hello world! #welcome ! first post on the instance :rainbow: !", 1327 Text: "hello world! #welcome ! first post on the instance :rainbow: !", 1328 AttachmentIDs: []string{"01F8MH6NEM8D7527KZAECTCR76"}, 1329 TagIDs: []string{"01F8MHA1A2NF9MJ3WCCQ3K8BSZ"}, 1330 MentionIDs: []string{}, 1331 EmojiIDs: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"}, 1332 CreatedAt: TimeMustParse("2021-10-20T11:36:45Z"), 1333 UpdatedAt: TimeMustParse("2021-10-20T11:36:45Z"), 1334 Local: TrueBool(), 1335 AccountURI: "http://localhost:8080/users/admin", 1336 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1337 InReplyToID: "", 1338 BoostOfID: "", 1339 ContentWarning: "", 1340 Visibility: gtsmodel.VisibilityPublic, 1341 Sensitive: FalseBool(), 1342 Language: "en", 1343 CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 1344 Federated: TrueBool(), 1345 Boostable: TrueBool(), 1346 Replyable: TrueBool(), 1347 Likeable: TrueBool(), 1348 ActivityStreamsType: ap.ObjectNote, 1349 }, 1350 "admin_account_status_2": { 1351 ID: "01F8MHAAY43M6RJ473VQFCVH37", 1352 PinnedAt: TimeMustParse("2022-05-14T14:21:09+02:00"), 1353 URI: "http://localhost:8080/users/admin/statuses/01F8MHAAY43M6RJ473VQFCVH37", 1354 URL: "http://localhost:8080/@admin/statuses/01F8MHAAY43M6RJ473VQFCVH37", 1355 Content: "🐕🐕🐕🐕🐕", 1356 Text: "🐕🐕🐕🐕🐕", 1357 CreatedAt: TimeMustParse("2021-10-20T12:36:45Z"), 1358 UpdatedAt: TimeMustParse("2021-10-20T12:36:45Z"), 1359 Local: TrueBool(), 1360 AccountURI: "http://localhost:8080/users/admin", 1361 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1362 InReplyToID: "", 1363 BoostOfID: "", 1364 ContentWarning: "open to see some puppies", 1365 Visibility: gtsmodel.VisibilityPublic, 1366 Sensitive: TrueBool(), 1367 Language: "en", 1368 CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 1369 Federated: TrueBool(), 1370 Boostable: TrueBool(), 1371 Replyable: TrueBool(), 1372 Likeable: TrueBool(), 1373 ActivityStreamsType: ap.ObjectNote, 1374 }, 1375 "admin_account_status_3": { 1376 ID: "01FF25D5Q0DH7CHD57CTRS6WK0", 1377 URI: "http://localhost:8080/users/admin/statuses/01FF25D5Q0DH7CHD57CTRS6WK0", 1378 URL: "http://localhost:8080/@admin/statuses/01FF25D5Q0DH7CHD57CTRS6WK0", 1379 Content: "hi @the_mighty_zork welcome to the instance!", 1380 Text: "hi @the_mighty_zork welcome to the instance!", 1381 CreatedAt: TimeMustParse("2021-11-20T13:32:16Z"), 1382 UpdatedAt: TimeMustParse("2021-11-20T13:32:16Z"), 1383 Local: TrueBool(), 1384 AccountURI: "http://localhost:8080/users/admin", 1385 MentionIDs: []string{"01FF26A6BGEKCZFWNEHXB2ZZ6M"}, 1386 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1387 InReplyToID: "01F8MHAMCHF6Y650WCRSCP4WMY", 1388 InReplyToAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1389 InReplyToURI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY", 1390 BoostOfID: "", 1391 Visibility: gtsmodel.VisibilityPublic, 1392 Sensitive: FalseBool(), 1393 Language: "en", 1394 CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 1395 Federated: TrueBool(), 1396 Boostable: TrueBool(), 1397 Replyable: TrueBool(), 1398 Likeable: TrueBool(), 1399 ActivityStreamsType: ap.ObjectNote, 1400 }, 1401 "admin_account_status_4": { 1402 ID: "01G36SF3V6Y6V5BF9P4R7PQG7G", 1403 URI: "http://localhost:8080/users/admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G", 1404 URL: "http://localhost:8080/@admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G", 1405 Content: "hello everyone!", 1406 Text: "hello everyone!", 1407 CreatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"), 1408 UpdatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"), 1409 Local: TrueBool(), 1410 AccountURI: "http://localhost:8080/users/admin", 1411 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1412 InReplyToID: "", 1413 InReplyToAccountID: "", 1414 InReplyToURI: "", 1415 BoostOfID: "01F8MHAMCHF6Y650WCRSCP4WMY", 1416 BoostOfAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1417 ContentWarning: "introduction post", 1418 Visibility: gtsmodel.VisibilityPublic, 1419 Sensitive: TrueBool(), 1420 Language: "en", 1421 CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 1422 Federated: TrueBool(), 1423 Boostable: TrueBool(), 1424 Replyable: TrueBool(), 1425 Likeable: TrueBool(), 1426 ActivityStreamsType: ap.ObjectNote, 1427 }, 1428 "local_account_1_status_1": { 1429 ID: "01F8MHAMCHF6Y650WCRSCP4WMY", 1430 URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY", 1431 URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY", 1432 Content: "hello everyone!", 1433 Text: "hello everyone!", 1434 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1435 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1436 Local: TrueBool(), 1437 AccountURI: "http://localhost:8080/users/the_mighty_zork", 1438 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1439 InReplyToID: "", 1440 BoostOfID: "", 1441 ContentWarning: "introduction post", 1442 Visibility: gtsmodel.VisibilityPublic, 1443 Sensitive: TrueBool(), 1444 Language: "en", 1445 CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 1446 Federated: TrueBool(), 1447 Boostable: TrueBool(), 1448 Replyable: TrueBool(), 1449 Likeable: TrueBool(), 1450 ActivityStreamsType: ap.ObjectNote, 1451 }, 1452 "local_account_1_status_2": { 1453 ID: "01F8MHAYFKS4KMXF8K5Y1C0KRN", 1454 URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAYFKS4KMXF8K5Y1C0KRN", 1455 URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MHAYFKS4KMXF8K5Y1C0KRN", 1456 Content: "this is an unlocked local-only post that shouldn't federate, but it's still boostable, replyable, and likeable", 1457 Text: "this is an unlocked local-only post that shouldn't federate, but it's still boostable, replyable, and likeable", 1458 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1459 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1460 Local: TrueBool(), 1461 AccountURI: "http://localhost:8080/users/the_mighty_zork", 1462 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1463 InReplyToID: "", 1464 BoostOfID: "", 1465 ContentWarning: "", 1466 Visibility: gtsmodel.VisibilityUnlocked, 1467 Sensitive: FalseBool(), 1468 Language: "en", 1469 CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 1470 Federated: FalseBool(), 1471 Boostable: TrueBool(), 1472 Replyable: TrueBool(), 1473 Likeable: TrueBool(), 1474 ActivityStreamsType: ap.ObjectNote, 1475 }, 1476 "local_account_1_status_3": { 1477 ID: "01F8MHBBN8120SYH7D5S050MGK", 1478 URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHBBN8120SYH7D5S050MGK", 1479 URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MHBBN8120SYH7D5S050MGK", 1480 Content: "this is a very personal post that I don't want anyone to interact with at all, and i only want mutuals to see it", 1481 Text: "this is a very personal post that I don't want anyone to interact with at all, and i only want mutuals to see it", 1482 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1483 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1484 Local: TrueBool(), 1485 AccountURI: "http://localhost:8080/users/the_mighty_zork", 1486 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1487 InReplyToID: "", 1488 BoostOfID: "", 1489 ContentWarning: "test: you shouldn't be able to interact with this post in any way", 1490 Visibility: gtsmodel.VisibilityMutualsOnly, 1491 Sensitive: FalseBool(), 1492 Language: "en", 1493 CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 1494 Federated: TrueBool(), 1495 Boostable: FalseBool(), 1496 Replyable: FalseBool(), 1497 Likeable: FalseBool(), 1498 ActivityStreamsType: ap.ObjectNote, 1499 }, 1500 "local_account_1_status_4": { 1501 ID: "01F8MH82FYRXD2RC6108DAJ5HB", 1502 URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB", 1503 URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB", 1504 Content: "here's a little gif of trent.... and also a cow", 1505 Text: "here's a little gif of trent.... and also a cow", 1506 AttachmentIDs: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ", "01CDR64G398ADCHXK08WWTHEZ5"}, 1507 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1508 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1509 Local: TrueBool(), 1510 AccountURI: "http://localhost:8080/users/the_mighty_zork", 1511 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1512 InReplyToID: "", 1513 BoostOfID: "", 1514 ContentWarning: "eye contact, trent reznor gif, cow", 1515 Visibility: gtsmodel.VisibilityMutualsOnly, 1516 Sensitive: FalseBool(), 1517 Language: "en", 1518 CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 1519 Federated: TrueBool(), 1520 Boostable: TrueBool(), 1521 Replyable: TrueBool(), 1522 Likeable: TrueBool(), 1523 ActivityStreamsType: ap.ObjectNote, 1524 }, 1525 "local_account_1_status_5": { 1526 ID: "01FCTA44PW9H1TB328S9AQXKDS", 1527 URI: "http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS", 1528 URL: "http://localhost:8080/@the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS", 1529 Content: "hi!", 1530 Text: "hi!", 1531 AttachmentIDs: []string{}, 1532 CreatedAt: TimeMustParse("2022-05-20T11:37:55Z"), 1533 UpdatedAt: TimeMustParse("2022-05-20T11:37:55Z"), 1534 Local: TrueBool(), 1535 AccountURI: "http://localhost:8080/users/the_mighty_zork", 1536 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1537 InReplyToID: "", 1538 BoostOfID: "", 1539 ContentWarning: "", 1540 Visibility: gtsmodel.VisibilityFollowersOnly, 1541 Sensitive: FalseBool(), 1542 Language: "en", 1543 CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", 1544 Federated: TrueBool(), 1545 Boostable: TrueBool(), 1546 Replyable: TrueBool(), 1547 Likeable: TrueBool(), 1548 ActivityStreamsType: ap.ObjectNote, 1549 }, 1550 "local_account_2_status_1": { 1551 ID: "01F8MHBQCBTDKN6X5VHGMMN4MA", 1552 URI: "http://localhost:8080/users/1happyturtle/statuses/01F8MHBQCBTDKN6X5VHGMMN4MA", 1553 URL: "http://localhost:8080/@1happyturtle/statuses/01F8MHBQCBTDKN6X5VHGMMN4MA", 1554 Content: "🐢 hi everyone i post about turtles 🐢", 1555 Text: "🐢 hi everyone i post about turtles 🐢", 1556 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1557 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1558 Local: TrueBool(), 1559 AccountURI: "http://localhost:8080/users/1happyturtle", 1560 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1561 InReplyToID: "", 1562 BoostOfID: "", 1563 ContentWarning: "introduction post", 1564 Visibility: gtsmodel.VisibilityPublic, 1565 Sensitive: TrueBool(), 1566 Language: "en", 1567 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1568 Federated: TrueBool(), 1569 Boostable: TrueBool(), 1570 Replyable: TrueBool(), 1571 Likeable: TrueBool(), 1572 ActivityStreamsType: ap.ObjectNote, 1573 }, 1574 "local_account_2_status_2": { 1575 ID: "01F8MHC0H0A7XHTVH5F596ZKBM", 1576 URI: "http://localhost:8080/users/1happyturtle/statuses/01F8MHC0H0A7XHTVH5F596ZKBM", 1577 URL: "http://localhost:8080/@1happyturtle/statuses/01F8MHC0H0A7XHTVH5F596ZKBM", 1578 Content: "🐢 this one is federated, likeable, and boostable but not replyable 🐢", 1579 Text: "🐢 this one is federated, likeable, and boostable but not replyable 🐢", 1580 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1581 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1582 Local: TrueBool(), 1583 AccountURI: "http://localhost:8080/users/1happyturtle", 1584 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1585 InReplyToID: "", 1586 BoostOfID: "", 1587 ContentWarning: "", 1588 Visibility: gtsmodel.VisibilityPublic, 1589 Sensitive: TrueBool(), 1590 Language: "en", 1591 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1592 Federated: TrueBool(), 1593 Boostable: TrueBool(), 1594 Replyable: FalseBool(), 1595 Likeable: TrueBool(), 1596 ActivityStreamsType: ap.ObjectNote, 1597 }, 1598 "local_account_2_status_3": { 1599 ID: "01F8MHC8VWDRBQR0N1BATDDEM5", 1600 URI: "http://localhost:8080/users/1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5", 1601 URL: "http://localhost:8080/@1happyturtle/statuses/01F8MHC8VWDRBQR0N1BATDDEM5", 1602 Content: "🐢 i don't mind people sharing this one but I don't want likes or replies to it because cba🐢", 1603 Text: "🐢 i don't mind people sharing this one but I don't want likes or replies to it because cba🐢", 1604 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1605 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1606 Local: TrueBool(), 1607 AccountURI: "http://localhost:8080/users/1happyturtle", 1608 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1609 InReplyToID: "", 1610 BoostOfID: "", 1611 ContentWarning: "you won't be able to like or reply to this", 1612 Visibility: gtsmodel.VisibilityUnlocked, 1613 Sensitive: TrueBool(), 1614 Language: "en", 1615 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1616 Federated: TrueBool(), 1617 Boostable: TrueBool(), 1618 Replyable: FalseBool(), 1619 Likeable: FalseBool(), 1620 ActivityStreamsType: ap.ObjectNote, 1621 }, 1622 "local_account_2_status_4": { 1623 ID: "01F8MHCP5P2NWYQ416SBA0XSEV", 1624 URI: "http://localhost:8080/users/1happyturtle/statuses/01F8MHCP5P2NWYQ416SBA0XSEV", 1625 URL: "http://localhost:8080/@1happyturtle/statuses/01F8MHCP5P2NWYQ416SBA0XSEV", 1626 Content: "🐢 this is a public status but I want it local only and not boostable 🐢", 1627 Text: "🐢 this is a public status but I want it local only and not boostable 🐢", 1628 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1629 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1630 Local: TrueBool(), 1631 AccountURI: "http://localhost:8080/users/1happyturtle", 1632 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1633 InReplyToID: "", 1634 BoostOfID: "", 1635 ContentWarning: "", 1636 Visibility: gtsmodel.VisibilityPublic, 1637 Sensitive: TrueBool(), 1638 Language: "en", 1639 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1640 Federated: FalseBool(), 1641 Boostable: FalseBool(), 1642 Replyable: TrueBool(), 1643 Likeable: TrueBool(), 1644 1645 ActivityStreamsType: ap.ObjectNote, 1646 }, 1647 "local_account_2_status_5": { 1648 ID: "01FCQSQ667XHJ9AV9T27SJJSX5", 1649 URI: "http://localhost:8080/users/1happyturtle/statuses/01FCQSQ667XHJ9AV9T27SJJSX5", 1650 URL: "http://localhost:8080/@1happyturtle/statuses/01FCQSQ667XHJ9AV9T27SJJSX5", 1651 Content: "🐢 @the_mighty_zork hi zork! 🐢", 1652 Text: "🐢 @the_mighty_zork hi zork! 🐢", 1653 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1654 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1655 Local: TrueBool(), 1656 AccountURI: "http://localhost:8080/users/1happyturtle", 1657 MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"}, 1658 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1659 InReplyToID: "01F8MHAMCHF6Y650WCRSCP4WMY", 1660 InReplyToAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1661 InReplyToURI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY", 1662 BoostOfID: "", 1663 ContentWarning: "", 1664 Visibility: gtsmodel.VisibilityPublic, 1665 Sensitive: FalseBool(), 1666 Language: "en", 1667 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1668 Federated: TrueBool(), 1669 Boostable: TrueBool(), 1670 Replyable: TrueBool(), 1671 Likeable: TrueBool(), 1672 ActivityStreamsType: ap.ObjectNote, 1673 }, 1674 "local_account_2_status_6": { 1675 ID: "01FN3VJGFH10KR7S2PB0GFJZYG", 1676 URI: "http://localhost:8080/users/1happyturtle/statuses/01FN3VJGFH10KR7S2PB0GFJZYG", 1677 URL: "http://localhost:8080/@1happyturtle/statuses/01FN3VJGFH10KR7S2PB0GFJZYG", 1678 Content: "🐢 @the_mighty_zork hi zork, this is a direct message, shhhhhh! 🐢", 1679 Text: "🐢 @the_mighty_zork hi zork, this is a direct message, shhhhhh! 🐢", 1680 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1681 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1682 Local: TrueBool(), 1683 AccountURI: "http://localhost:8080/users/1happyturtle", 1684 MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"}, 1685 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1686 InReplyToID: "", 1687 InReplyToAccountID: "", 1688 InReplyToURI: "", 1689 BoostOfID: "", 1690 ContentWarning: "", 1691 Visibility: gtsmodel.VisibilityDirect, 1692 Sensitive: FalseBool(), 1693 Language: "en", 1694 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1695 Federated: TrueBool(), 1696 Boostable: TrueBool(), 1697 Replyable: TrueBool(), 1698 Likeable: TrueBool(), 1699 ActivityStreamsType: ap.ObjectNote, 1700 }, 1701 "local_account_2_status_7": { 1702 ID: "01G20ZM733MGN8J344T4ZDDFY1", 1703 PinnedAt: TimeMustParse("2021-03-18T09:13:55+02:00"), 1704 URI: "http://localhost:8080/users/1happyturtle/statuses/01G20ZM733MGN8J344T4ZDDFY1", 1705 URL: "http://localhost:8080/@1happyturtle/statuses/01G20ZM733MGN8J344T4ZDDFY1", 1706 Content: "🐢 hi followers! did u know i'm a turtle? 🐢", 1707 Text: "🐢 hi followers! did u know i'm a turtle? 🐢", 1708 AttachmentIDs: []string{}, 1709 CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1710 UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), 1711 Local: TrueBool(), 1712 AccountURI: "http://localhost:8080/users/1happyturtle", 1713 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1714 InReplyToID: "", 1715 BoostOfID: "", 1716 ContentWarning: "", 1717 Visibility: gtsmodel.VisibilityFollowersOnly, 1718 Sensitive: FalseBool(), 1719 Language: "en", 1720 CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", 1721 Federated: TrueBool(), 1722 Boostable: TrueBool(), 1723 Replyable: TrueBool(), 1724 Likeable: TrueBool(), 1725 ActivityStreamsType: ap.ObjectNote, 1726 }, 1727 "remote_account_1_status_1": { 1728 ID: "01FVW7JHQFSFK166WWKR8CBA6M", 1729 URI: "http://fossbros-anonymous.io/users/foss_satan/statuses/01FVW7JHQFSFK166WWKR8CBA6M", 1730 URL: "http://fossbros-anonymous.io/@foss_satan/statuses/01FVW7JHQFSFK166WWKR8CBA6M", 1731 Content: "dark souls status bot: \"thoughts of dog\"", 1732 AttachmentIDs: []string{"01FVW7RXPQ8YJHTEXYPE7Q8ZY0"}, 1733 CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1734 UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), 1735 Local: FalseBool(), 1736 AccountURI: "http://fossbros-anonymous.io/users/foss_satan", 1737 MentionIDs: []string{}, 1738 AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 1739 InReplyToID: "", 1740 InReplyToAccountID: "", 1741 InReplyToURI: "", 1742 BoostOfID: "", 1743 ContentWarning: "", 1744 Visibility: gtsmodel.VisibilityUnlocked, 1745 Sensitive: FalseBool(), 1746 Language: "en", 1747 CreatedWithApplicationID: "", 1748 Federated: TrueBool(), 1749 Boostable: TrueBool(), 1750 Replyable: TrueBool(), 1751 Likeable: TrueBool(), 1752 ActivityStreamsType: ap.ObjectNote, 1753 }, 1754 } 1755 } 1756 1757 // NewTestTags returns a map of gts model tags keyed by their name 1758 func NewTestTags() map[string]*gtsmodel.Tag { 1759 return map[string]*gtsmodel.Tag{ 1760 "welcome": { 1761 ID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ", 1762 URL: "http://localhost:8080/tags/welcome", 1763 Name: "welcome", 1764 FirstSeenFromAccountID: "", 1765 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1766 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1767 Useable: TrueBool(), 1768 Listable: TrueBool(), 1769 LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1770 }, 1771 "Hashtag": { 1772 ID: "01FCT9SGYA71487N8D0S1M638G", 1773 URL: "http://localhost:8080/tags/Hashtag", 1774 Name: "Hashtag", 1775 FirstSeenFromAccountID: "", 1776 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1777 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1778 Useable: TrueBool(), 1779 Listable: TrueBool(), 1780 LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1781 }, 1782 } 1783 } 1784 1785 func NewTestStatusToTags() map[string]*gtsmodel.StatusToTag { 1786 return map[string]*gtsmodel.StatusToTag{ 1787 "admin_account_status_1_welcome": { 1788 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", 1789 TagID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ", 1790 }, 1791 } 1792 } 1793 1794 // NewTestMentions returns a map of gts model mentions keyed by their name. 1795 func NewTestMentions() map[string]*gtsmodel.Mention { 1796 return map[string]*gtsmodel.Mention{ 1797 "zork_mention_foss_satan": { 1798 ID: "01FCTA2Y6FGHXQA4ZE6N5NMNEX", 1799 StatusID: "01FCTA44PW9H1TB328S9AQXKDS", 1800 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1801 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1802 OriginAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1803 OriginAccountURI: "http://localhost:8080/users/the_mighty_zork", 1804 TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 1805 NameString: "@foss_satan@fossbros-anonymous.io", 1806 TargetAccountURI: "http://fossbros-anonymous.io/users/foss_satan", 1807 TargetAccountURL: "http://fossbros-anonymous.io/@foss_satan", 1808 }, 1809 "local_user_2_mention_zork": { 1810 ID: "01FDF2HM2NF6FSRZCDEDV451CN", 1811 StatusID: "01FCQSQ667XHJ9AV9T27SJJSX5", 1812 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1813 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1814 OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1815 OriginAccountURI: "http://localhost:8080/users/1happyturtle", 1816 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1817 NameString: "@the_mighty_zork", 1818 TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", 1819 TargetAccountURL: "http://localhost:8080/@the_mighty_zork", 1820 }, 1821 "local_user_2_mention_zork_direct_message": { 1822 ID: "01FN3VKDEF4CN2W9TKX339BEHB", 1823 StatusID: "01FN3VJGFH10KR7S2PB0GFJZYG", 1824 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1825 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1826 OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1827 OriginAccountURI: "http://localhost:8080/users/1happyturtle", 1828 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1829 NameString: "@the_mighty_zork", 1830 TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", 1831 TargetAccountURL: "http://localhost:8080/@the_mighty_zork", 1832 }, 1833 "admin_account_mention_zork": { 1834 ID: "01FF26A6BGEKCZFWNEHXB2ZZ6M", 1835 StatusID: "01FF25D5Q0DH7CHD57CTRS6WK0", 1836 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1837 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1838 OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1839 OriginAccountURI: "http://localhost:8080/users/admin", 1840 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1841 NameString: "@the_mighty_zork", 1842 TargetAccountURI: "http://localhost:8080/users/the_mighty_zork", 1843 TargetAccountURL: "http://localhost:8080/@the_mighty_zork", 1844 }, 1845 } 1846 } 1847 1848 // NewTestFaves returns a map of gts model faves, keyed in the format [faving_account]_[target_status] 1849 func NewTestFaves() map[string]*gtsmodel.StatusFave { 1850 return map[string]*gtsmodel.StatusFave{ 1851 "local_account_1_admin_account_status_1": { 1852 ID: "01F8MHD2QCZSZ6WQS2ATVPEYJ9", 1853 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1854 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 1855 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account 1856 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", // admin account status 1 1857 URI: "http://localhost:8080/users/the_mighty_zork/liked/01F8MHD2QCZSZ6WQS2ATVPEYJ9", 1858 }, 1859 "local_account_1_admin_account_status_3": { 1860 ID: "01GM435XERVPXXRK6NBAHK5HCZ", 1861 CreatedAt: TimeMustParse("2022-12-12T20:17:56+02:00"), 1862 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 1863 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account 1864 StatusID: "01F8MHAAY43M6RJ473VQFCVH37", // admin account status 1 1865 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM435XERVPXXRK6NBAHK5HCZ", 1866 }, 1867 "local_account_1_local_account_2_status_1": { 1868 ID: "01GM43AKBMN4YNXQ1HZHVC1SGB", 1869 CreatedAt: TimeMustParse("2022-12-12T20:19:49+02:00"), 1870 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 1871 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", // admin account 1872 StatusID: "01F8MHBQCBTDKN6X5VHGMMN4MA", // admin account status 1 1873 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM43AKBMN4YNXQ1HZHVC1SGB", 1874 }, 1875 "local_account_1_local_account_2_status_4": { 1876 ID: "01GM43CC47DRPNZZ7BD04BS1YZ", 1877 CreatedAt: TimeMustParse("2022-12-12T20:20:47+02:00"), 1878 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 1879 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", // admin account 1880 StatusID: "01F8MHCP5P2NWYQ416SBA0XSEV", // admin account status 1 1881 URI: "http://localhost:8080/users/the_mighty_zork/liked/01GM43CC47DRPNZZ7BD04BS1YZ", 1882 }, 1883 "admin_account_local_account_1_status_1": { 1884 ID: "01F8Q0486ANTDWKG02A7DS1Q24", 1885 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1886 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account 1887 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 1888 StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", // local account status 1 1889 URI: "http://localhost:8080/users/admin/liked/01F8Q0486ANTDWKG02A7DS1Q24", 1890 }, 1891 } 1892 } 1893 1894 // NewTestNotifications returns some notifications for use in testing. 1895 func NewTestNotifications() map[string]*gtsmodel.Notification { 1896 return map[string]*gtsmodel.Notification{ 1897 "local_account_1_like": { 1898 ID: "01F8Q0ANPTWW10DAKTX7BRPBJP", 1899 NotificationType: gtsmodel.NotificationFave, 1900 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1901 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1902 OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1903 StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", 1904 Read: FalseBool(), 1905 }, 1906 "local_account_2_like": { 1907 ID: "01GTS6PRPXJYZBPFFQ56PP0XR8", 1908 NotificationType: gtsmodel.NotificationFave, 1909 CreatedAt: TimeMustParse("2022-01-13T12:45:01+02:00"), 1910 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1911 OriginAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1912 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", 1913 Read: FalseBool(), 1914 }, 1915 } 1916 } 1917 1918 // NewTestFollows returns some follows for use in testing. 1919 func NewTestFollows() map[string]*gtsmodel.Follow { 1920 return map[string]*gtsmodel.Follow{ 1921 "local_account_1_admin_account": { 1922 ID: "01F8PY8RHWRQZV038T4E8T9YK8", 1923 CreatedAt: TimeMustParse("2022-05-14T16:21:09+02:00"), 1924 UpdatedAt: TimeMustParse("2022-05-14T16:21:09+02:00"), 1925 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1926 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1927 ShowReblogs: TrueBool(), 1928 URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PY8RHWRQZV038T4E8T9YK8", 1929 Notify: FalseBool(), 1930 }, 1931 "local_account_1_local_account_2": { 1932 ID: "01F8PYDCE8XE23GRE5DPZJDZDP", 1933 CreatedAt: TimeMustParse("2022-05-14T15:21:09+02:00"), 1934 UpdatedAt: TimeMustParse("2022-05-14T15:21:09+02:00"), 1935 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1936 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1937 ShowReblogs: TrueBool(), 1938 URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PYDCE8XE23GRE5DPZJDZDP", 1939 Notify: FalseBool(), 1940 }, 1941 "local_account_2_local_account_1": { 1942 ID: "01G1TK1RS4K3E0MSFTXBFWAH9Q", 1943 CreatedAt: TimeMustParse("2022-05-14T14:21:09+02:00"), 1944 UpdatedAt: TimeMustParse("2022-05-14T14:21:09+02:00"), 1945 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 1946 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1947 ShowReblogs: TrueBool(), 1948 URI: "http://localhost:8080/users/1happyturtle/follow/01F8PYDCE8XE23GRE5DPZJDZDP", 1949 Notify: FalseBool(), 1950 }, 1951 "admin_account_local_account_1": { 1952 ID: "01G1TK3PQKFW1BQZ9WVYRTFECK", 1953 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1954 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1955 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 1956 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1957 ShowReblogs: TrueBool(), 1958 URI: "http://localhost:8080/users/admin/follow/01G1TK3PQKFW1BQZ9WVYRTFECK", 1959 Notify: FalseBool(), 1960 }, 1961 } 1962 } 1963 1964 func NewTestLists() map[string]*gtsmodel.List { 1965 return map[string]*gtsmodel.List{ 1966 "local_account_1_list_1": { 1967 ID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", 1968 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1969 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1970 Title: "Cool Ass Posters From This Instance", 1971 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", 1972 RepliesPolicy: gtsmodel.RepliesPolicyFollowed, 1973 }, 1974 } 1975 } 1976 1977 func NewTestListEntries() map[string]*gtsmodel.ListEntry { 1978 return map[string]*gtsmodel.ListEntry{ 1979 "local_account_1_list_1_entry_1": { 1980 ID: "01H0G89MWVQE0M58VD2HQYMQWH", 1981 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1982 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1983 ListID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", 1984 FollowID: "01F8PYDCE8XE23GRE5DPZJDZDP", 1985 }, 1986 "local_account_1_list_1_entry_2": { 1987 ID: "01H0G8FFM1AGQDRNGBGGX8CYJQ", 1988 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1989 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 1990 ListID: "01H0G8E4Q2J3FE3JDWJVWEDCD1", 1991 FollowID: "01F8PY8RHWRQZV038T4E8T9YK8", 1992 }, 1993 } 1994 } 1995 1996 func NewTestBlocks() map[string]*gtsmodel.Block { 1997 return map[string]*gtsmodel.Block{ 1998 "local_account_2_block_remote_account_1": { 1999 ID: "01FEXXET6XXMF7G2V3ASZP3YQW", 2000 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 2001 UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 2002 URI: "http://localhost:8080/users/1happyturtle/blocks/01FEXXET6XXMF7G2V3ASZP3YQW", 2003 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 2004 TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 2005 }, 2006 } 2007 } 2008 2009 func NewTestReports() map[string]*gtsmodel.Report { 2010 return map[string]*gtsmodel.Report{ 2011 "local_account_2_report_remote_account_1": { 2012 ID: "01GP3AWY4CRDVRNZKW0TEAMB5R", 2013 CreatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), 2014 UpdatedAt: TimeMustParse("2022-05-14T12:20:03+02:00"), 2015 URI: "http://localhost:8080/reports/01GP3AWY4CRDVRNZKW0TEAMB5R", 2016 AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 2017 TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 2018 Comment: "dark souls sucks, please yeet this nerd", 2019 StatusIDs: []string{"01FVW7JHQFSFK166WWKR8CBA6M"}, 2020 Forwarded: TrueBool(), 2021 }, 2022 "remote_account_1_report_local_account_2": { 2023 ID: "01GP3DFY9XQ1TJMZT5BGAZPXX7", 2024 CreatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), 2025 UpdatedAt: TimeMustParse("2022-05-15T16:20:12+02:00"), 2026 URI: "http://fossbros-anonymous.io/87fb1478-ac46-406a-8463-96ce05645219", 2027 AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", 2028 TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", 2029 Comment: "this is a turtle, not a person, therefore should not be a poster", 2030 StatusIDs: []string{}, 2031 Forwarded: TrueBool(), 2032 ActionTaken: "user was warned not to be a turtle anymore", 2033 ActionTakenAt: TimeMustParse("2022-05-15T17:01:56+02:00"), 2034 ActionTakenByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 2035 }, 2036 } 2037 } 2038 2039 // ActivityWithSignature wraps a pub.Activity along with its signature headers, for testing. 2040 type ActivityWithSignature struct { 2041 Activity pub.Activity 2042 SignatureHeader string 2043 DigestHeader string 2044 DateHeader string 2045 } 2046 2047 // NewTestActivities returns a bunch of pub.Activity types for use in testing the federation protocols. 2048 // A struct of accounts needs to be passed in because the activities will also be bundled along with 2049 // their requesting signatures. 2050 func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]ActivityWithSignature { 2051 dmForZork := NewAPNote( 2052 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6"), 2053 URLMustParse("http://fossbros-anonymous.io/@foss_satan/5424b153-4553-4f30-9358-7b92f7cd42f6"), 2054 TimeMustParse("2022-07-13T12:13:12+02:00"), 2055 "hey zork here's a new private note for you", 2056 "new note for zork", 2057 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2058 []*url.URL{URLMustParse("http://localhost:8080/users/the_mighty_zork")}, 2059 nil, 2060 true, 2061 []vocab.ActivityStreamsMention{}, 2062 nil, 2063 ) 2064 createDmForZork := WrapAPNoteInCreate( 2065 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/5424b153-4553-4f30-9358-7b92f7cd42f6/activity"), 2066 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2067 TimeMustParse("2022-07-13T12:13:12+02:00"), 2068 dmForZork) 2069 createDmForZorkSig, createDmForZorkDigest, creatDmForZorkDate := GetSignatureForActivity(createDmForZork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) 2070 2071 replyToTurtle := NewAPNote( 2072 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), 2073 URLMustParse("http://fossbros-anonymous.io/@foss_satan/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), 2074 TimeMustParse("2022-07-13T12:13:12+02:00"), 2075 "@1happyturtle@localhost:8080 u suck lol", 2076 "", 2077 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2078 []*url.URL{URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers")}, 2079 []*url.URL{URLMustParse("http://localhost:8080/users/1happyturtle")}, 2080 false, 2081 []vocab.ActivityStreamsMention{newAPMention( 2082 URLMustParse("http://localhost:8080/users/1happyturtle"), 2083 "@1happyturtle@localhost:8080", 2084 )}, 2085 nil, 2086 ) 2087 createReplyToTurtle := WrapAPNoteInCreate( 2088 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/2f1195a6-5cb0-4475-adf5-92ab9a0147fe"), 2089 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2090 TimeMustParse("2022-07-13T12:13:12+02:00"), 2091 replyToTurtle) 2092 createReplyToTurtleForZorkSig, createReplyToTurtleForZorkDigest, createReplyToTurtleForZorkDate := GetSignatureForActivity(createReplyToTurtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) 2093 createReplyToTurtleForTurtleSig, createReplyToTurtleForTurtleDigest, createReplyToTurtleForTurtleDate := GetSignatureForActivity(createReplyToTurtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_2"].InboxURI)) 2094 2095 forwardedMessage := NewAPNote( 2096 URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"), 2097 URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"), 2098 TimeMustParse("2022-07-13T12:13:12+02:00"), 2099 "this is a public status, please forward it!", 2100 "", 2101 URLMustParse("http://example.org/users/Some_User"), 2102 []*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, 2103 nil, 2104 false, 2105 []vocab.ActivityStreamsMention{}, 2106 []vocab.ActivityStreamsImage{ 2107 newAPImage( 2108 URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"), 2109 "image/jpeg", 2110 "trent reznor looking handsome as balls", 2111 "LEDara58O=t5EMSOENEN9]}?aK%0"), 2112 }, 2113 ) 2114 createForwardedMessage := WrapAPNoteInCreate( 2115 URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/activity"), 2116 URLMustParse("http://example.org/users/Some_User"), 2117 TimeMustParse("2022-07-13T12:13:12+02:00"), 2118 forwardedMessage) 2119 createForwardedMessageSig, createForwardedMessageDigest, createForwardedMessageDate := GetSignatureForActivity(createForwardedMessage, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) 2120 2121 announceForwarded1Zork := newAPAnnounce( 2122 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/first_announce"), 2123 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2124 TimeMustParse("2022-07-13T12:13:12+02:00"), 2125 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), 2126 forwardedMessage, 2127 ) 2128 announceForwarded1ZorkSig, announceForwarded1ZorkDigest, announceForwarded1ZorkDate := GetSignatureForActivity(announceForwarded1Zork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) 2129 2130 announceForwarded1Turtle := newAPAnnounce( 2131 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/first_announce"), 2132 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2133 TimeMustParse("2022-07-13T12:13:12+02:00"), 2134 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), 2135 forwardedMessage, 2136 ) 2137 announceForwarded1TurtleSig, announceForwarded1TurtleDigest, announceForwarded1TurtleDate := GetSignatureForActivity(announceForwarded1Turtle, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_2"].InboxURI)) 2138 2139 announceForwarded2Zork := newAPAnnounce( 2140 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/second_announce"), 2141 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2142 TimeMustParse("2022-07-13T12:13:12+02:00"), 2143 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/followers"), 2144 forwardedMessage, 2145 ) 2146 announceForwarded2ZorkSig, announceForwarded2ZorkDigest, announceForwarded2ZorkDate := GetSignatureForActivity(announceForwarded2Zork, accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, URLMustParse(accounts["local_account_1"].InboxURI)) 2147 2148 deleteForRemoteAccount3 := newAPDelete( 2149 URLMustParse("https://somewhere.mysterious/users/rest_in_piss"), 2150 URLMustParse("https://somewhere.mysterious/users/rest_in_piss"), 2151 TimeMustParse("2022-07-13T12:13:12+02:00"), 2152 URLMustParse(accounts["local_account_1"].URI), 2153 ) 2154 // it doesn't really matter what key we use to sign this, since we're not going to be able to verify if anyway 2155 keyToSignDelete := accounts["remote_account_1"].PrivateKey 2156 deleteForRemoteAccount3Sig, deleteForRemoteAccount3Digest, deleteForRemoteAccount3Date := GetSignatureForActivity(deleteForRemoteAccount3, "https://somewhere.mysterious/users/rest_in_piss#main-key", keyToSignDelete, URLMustParse(accounts["local_account_1"].InboxURI)) 2157 2158 return map[string]ActivityWithSignature{ 2159 "dm_for_zork": { 2160 Activity: createDmForZork, 2161 SignatureHeader: createDmForZorkSig, 2162 DigestHeader: createDmForZorkDigest, 2163 DateHeader: creatDmForZorkDate, 2164 }, 2165 "reply_to_turtle_for_zork": { 2166 Activity: createReplyToTurtle, 2167 SignatureHeader: createReplyToTurtleForZorkSig, 2168 DigestHeader: createReplyToTurtleForZorkDigest, 2169 DateHeader: createReplyToTurtleForZorkDate, 2170 }, 2171 "reply_to_turtle_for_turtle": { 2172 Activity: createReplyToTurtle, 2173 SignatureHeader: createReplyToTurtleForTurtleSig, 2174 DigestHeader: createReplyToTurtleForTurtleDigest, 2175 DateHeader: createReplyToTurtleForTurtleDate, 2176 }, 2177 "forwarded_message": { 2178 Activity: createForwardedMessage, 2179 SignatureHeader: createForwardedMessageSig, 2180 DigestHeader: createForwardedMessageDigest, 2181 DateHeader: createForwardedMessageDate, 2182 }, 2183 "announce_forwarded_1_zork": { 2184 Activity: announceForwarded1Zork, 2185 SignatureHeader: announceForwarded1ZorkSig, 2186 DigestHeader: announceForwarded1ZorkDigest, 2187 DateHeader: announceForwarded1ZorkDate, 2188 }, 2189 "announce_forwarded_1_turtle": { 2190 Activity: announceForwarded1Turtle, 2191 SignatureHeader: announceForwarded1TurtleSig, 2192 DigestHeader: announceForwarded1TurtleDigest, 2193 DateHeader: announceForwarded1TurtleDate, 2194 }, 2195 "announce_forwarded_2_zork": { 2196 Activity: announceForwarded2Zork, 2197 SignatureHeader: announceForwarded2ZorkSig, 2198 DigestHeader: announceForwarded2ZorkDigest, 2199 DateHeader: announceForwarded2ZorkDate, 2200 }, 2201 "delete_https://somewhere.mysterious/users/rest_in_piss#main-key": { 2202 Activity: deleteForRemoteAccount3, 2203 SignatureHeader: deleteForRemoteAccount3Sig, 2204 DigestHeader: deleteForRemoteAccount3Digest, 2205 DateHeader: deleteForRemoteAccount3Date, 2206 }, 2207 } 2208 } 2209 2210 // NewTestFediPeople returns a bunch of activity pub Person representations for testing converters and so on. 2211 func NewTestFediPeople() map[string]vocab.ActivityStreamsPerson { 2212 newPerson1Priv, err := rsa.GenerateKey(rand.Reader, 2048) 2213 if err != nil { 2214 panic(err) 2215 } 2216 newPerson1Pub := &newPerson1Priv.PublicKey 2217 2218 turnipLover6969Priv, err := rsa.GenerateKey(rand.Reader, 2048) 2219 if err != nil { 2220 panic(err) 2221 } 2222 turnipLover6969Pub := &turnipLover6969Priv.PublicKey 2223 2224 someUserPriv, err := rsa.GenerateKey(rand.Reader, 2048) 2225 if err != nil { 2226 panic(err) 2227 } 2228 someUserPub := &someUserPriv.PublicKey 2229 2230 return map[string]vocab.ActivityStreamsPerson{ 2231 "https://unknown-instance.com/users/brand_new_person": newAPPerson( 2232 URLMustParse("https://unknown-instance.com/users/brand_new_person"), 2233 URLMustParse("https://unknown-instance.com/users/brand_new_person/following"), 2234 URLMustParse("https://unknown-instance.com/users/brand_new_person/followers"), 2235 URLMustParse("https://unknown-instance.com/users/brand_new_person/inbox"), 2236 nil, 2237 URLMustParse("https://unknown-instance.com/users/brand_new_person/outbox"), 2238 URLMustParse("https://unknown-instance.com/users/brand_new_person/collections/featured"), 2239 "brand_new_person", 2240 "Geoff Brando New Personson", 2241 "hey I'm a new person, your instance hasn't seen me yet uwu", 2242 URLMustParse("https://unknown-instance.com/@brand_new_person"), 2243 true, 2244 URLMustParse("https://unknown-instance.com/users/brand_new_person#main-key"), 2245 newPerson1Pub, 2246 nil, 2247 "image/jpeg", 2248 nil, 2249 "image/png", 2250 false, 2251 ), 2252 "https://turnip.farm/users/turniplover6969": newAPPerson( 2253 URLMustParse("https://turnip.farm/users/turniplover6969"), 2254 URLMustParse("https://turnip.farm/users/turniplover6969/following"), 2255 URLMustParse("https://turnip.farm/users/turniplover6969/followers"), 2256 URLMustParse("https://turnip.farm/users/turniplover6969/inbox"), 2257 URLMustParse("https://turnip.farm/sharedInbox"), 2258 URLMustParse("https://turnip.farm/users/turniplover6969/outbox"), 2259 URLMustParse("https://turnip.farm/users/turniplover6969/collections/featured"), 2260 "turniplover6969", 2261 "Turnip Lover 6969", 2262 "I just think they're neat", 2263 URLMustParse("https://turnip.farm/@turniplover6969"), 2264 true, 2265 URLMustParse("https://turnip.farm/users/turniplover6969#main-key"), 2266 turnipLover6969Pub, 2267 nil, 2268 "image/jpeg", 2269 nil, 2270 "image/png", 2271 false, 2272 ), 2273 "https://example.org/users/Some_User": newAPPerson( 2274 URLMustParse("https://example.org/users/Some_User"), 2275 URLMustParse("https://example.org/users/Some_User/following"), 2276 URLMustParse("https://example.org/users/Some_User/followers"), 2277 URLMustParse("https://example.org/users/Some_User/inbox"), 2278 URLMustParse("https://example.org/sharedInbox"), 2279 URLMustParse("https://example.org/users/Some_User/outbox"), 2280 URLMustParse("https://example.org/users/Some_User/collections/featured"), 2281 "Some_User", 2282 "just some user, don't mind me", 2283 "Peepee poo poo", 2284 URLMustParse("https://example.org/@Some_User"), 2285 true, 2286 URLMustParse("https://example.org/users/Some_User#main-key"), 2287 someUserPub, 2288 nil, 2289 "image/jpeg", 2290 nil, 2291 "image/png", 2292 false, 2293 ), 2294 } 2295 } 2296 2297 func NewTestFediGroups() map[string]vocab.ActivityStreamsGroup { 2298 newGroup1Priv, err := rsa.GenerateKey(rand.Reader, 2048) 2299 if err != nil { 2300 panic(err) 2301 } 2302 newGroup1Pub := &newGroup1Priv.PublicKey 2303 2304 return map[string]vocab.ActivityStreamsGroup{ 2305 "https://unknown-instance.com/groups/some_group": newAPGroup( 2306 URLMustParse("https://unknown-instance.com/groups/some_group"), 2307 URLMustParse("https://unknown-instance.com/groups/some_group/following"), 2308 URLMustParse("https://unknown-instance.com/groups/some_group/followers"), 2309 URLMustParse("https://unknown-instance.com/groups/some_group/inbox"), 2310 URLMustParse("https://unknown-instance.com/groups/some_group/outbox"), 2311 URLMustParse("https://unknown-instance.com/groups/some_group/collections/featured"), 2312 "some_group", 2313 "This is a group about... something?", 2314 "", 2315 URLMustParse("https://unknown-instance.com/@some_group"), 2316 true, 2317 URLMustParse("https://unknown-instance.com/groups/some_group#main-key"), 2318 newGroup1Pub, 2319 nil, 2320 "image/jpeg", 2321 nil, 2322 "image/png", 2323 false, 2324 ), 2325 } 2326 } 2327 2328 func NewTestFediServices() map[string]vocab.ActivityStreamsService { 2329 newService1Priv, err := rsa.GenerateKey(rand.Reader, 2048) 2330 if err != nil { 2331 panic(err) 2332 } 2333 newService1Pub := &newService1Priv.PublicKey 2334 2335 return map[string]vocab.ActivityStreamsService{ 2336 "https://owncast.example.org/federation/user/rgh": newAPService( 2337 URLMustParse("https://owncast.example.org/federation/user/rgh"), 2338 nil, 2339 URLMustParse("https://owncast.example.org/federation/user/rgh/followers"), 2340 URLMustParse("https://owncast.example.org/federation/user/rgh/inbox"), 2341 URLMustParse("https://owncast.example.org/federation/user/rgh/outbox"), 2342 nil, 2343 "rgh", 2344 "linux audio stuff ", 2345 "", 2346 URLMustParse("https://owncast.example.org/federation/user/rgh"), 2347 true, 2348 URLMustParse("https://owncast.example.org/federation/user/rgh#main-key"), 2349 newService1Pub, 2350 nil, 2351 "image/jpeg", 2352 nil, 2353 "image/png", 2354 false, 2355 ), 2356 } 2357 } 2358 2359 func NewTestFediEmojis() map[string]vocab.TootEmoji { 2360 return map[string]vocab.TootEmoji{ 2361 "http://fossbros-anonymous.io/emoji/01GD5HCC2YECT012TK8PAGX4D1": newAPEmoji( 2362 URLMustParse("http://fossbros-anonymous.io/emoji/01GD5HCC2YECT012TK8PAGX4D1"), 2363 "kip_van_den_bos", 2364 TimeMustParse("2022-09-13T12:13:12+02:00"), 2365 newAPImage( 2366 URLMustParse("http://fossbros-anonymous.io/emoji/kip.gif"), 2367 "image/gif", 2368 "", 2369 "", 2370 ), 2371 ), 2372 } 2373 } 2374 2375 // RemoteAttachmentFile mimics a remote (federated) attachment 2376 type RemoteAttachmentFile struct { 2377 Data []byte 2378 ContentType string 2379 } 2380 2381 func NewTestFediAttachments(relativePath string) map[string]RemoteAttachmentFile { 2382 beeBytes, err := os.ReadFile(fmt.Sprintf("%s/beeplushie.jpg", relativePath)) 2383 if err != nil { 2384 panic(err) 2385 } 2386 2387 thoughtsOfDogBytes, err := os.ReadFile(fmt.Sprintf("%s/thoughtsofdog-original.jpg", relativePath)) 2388 if err != nil { 2389 panic(err) 2390 } 2391 2392 massiveFuckingTurnipBytes, err := os.ReadFile(fmt.Sprintf("%s/giant-turnip-world-record.jpg", relativePath)) 2393 if err != nil { 2394 panic(err) 2395 } 2396 2397 peglinBytes, err := os.ReadFile(fmt.Sprintf("%s/peglin.gif", relativePath)) 2398 if err != nil { 2399 panic(err) 2400 } 2401 2402 kipBytes, err := os.ReadFile(fmt.Sprintf("%s/kip-original.gif", relativePath)) 2403 if err != nil { 2404 panic(err) 2405 } 2406 2407 yellBytes, err := os.ReadFile(fmt.Sprintf("%s/yell-original.png", relativePath)) 2408 if err != nil { 2409 panic(err) 2410 } 2411 2412 return map[string]RemoteAttachmentFile{ 2413 "https://s3-us-west-2.amazonaws.com/plushcity/media_attachments/files/106/867/380/219/163/828/original/88e8758c5f011439.jpg": { 2414 Data: beeBytes, 2415 ContentType: "image/jpeg", 2416 }, 2417 "http://fossbros-anonymous.io/attachments/original/13bbc3f8-2b5e-46ea-9531-40b4974d9912.jpg": { 2418 Data: thoughtsOfDogBytes, 2419 ContentType: "image/jpeg", 2420 }, 2421 "https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg": { 2422 Data: massiveFuckingTurnipBytes, 2423 ContentType: "image/jpeg", 2424 }, 2425 "http://example.org/media/emojis/1781772.gif": { 2426 Data: peglinBytes, 2427 ContentType: "image/gif", 2428 }, 2429 "http://fossbros-anonymous.io/emoji/kip.gif": { 2430 Data: kipBytes, 2431 ContentType: "image/gif", 2432 }, 2433 "http://fossbros-anonymous.io/emoji/yell.gif": { 2434 Data: yellBytes, 2435 ContentType: "image/png", 2436 }, 2437 } 2438 } 2439 2440 func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote { 2441 return map[string]vocab.ActivityStreamsNote{ 2442 "http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1": NewAPNote( 2443 URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1"), 2444 URLMustParse("http://example.org/@Some_User/afaba698-5740-4e32-a702-af61aa543bc1"), 2445 TimeMustParse("2022-07-13T12:13:12+02:00"), 2446 "this is a public status, please forward it!", 2447 "", 2448 URLMustParse("http://example.org/users/Some_User"), 2449 []*url.URL{URLMustParse(pub.PublicActivityPubIRI)}, 2450 nil, 2451 false, 2452 []vocab.ActivityStreamsMention{}, 2453 []vocab.ActivityStreamsImage{ 2454 newAPImage( 2455 URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"), 2456 "image/jpeg", 2457 "trent reznor looking handsome as balls", 2458 "LEDara58O=t5EMSOENEN9]}?aK%0"), 2459 }, 2460 ), 2461 "https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839": NewAPNote( 2462 URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839"), 2463 URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839"), 2464 TimeMustParse("2022-07-13T12:13:12+02:00"), 2465 "Hello world!", 2466 "", 2467 URLMustParse("https://unknown-instance.com/users/brand_new_person"), 2468 []*url.URL{ 2469 URLMustParse(pub.PublicActivityPubIRI), 2470 }, 2471 []*url.URL{}, 2472 false, 2473 nil, 2474 nil, 2475 ), 2476 "https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV": NewAPNote( 2477 URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV"), 2478 URLMustParse("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV"), 2479 TimeMustParse("2022-07-13T12:13:12+02:00"), 2480 "Hey @the_mighty_zork@localhost:8080 how's it going?", 2481 "", 2482 URLMustParse("https://unknown-instance.com/users/brand_new_person"), 2483 []*url.URL{ 2484 URLMustParse(pub.PublicActivityPubIRI), 2485 }, 2486 []*url.URL{}, 2487 false, 2488 []vocab.ActivityStreamsMention{ 2489 newAPMention( 2490 URLMustParse("http://localhost:8080/users/the_mighty_zork"), 2491 "@the_mighty_zork@localhost:8080", 2492 ), 2493 }, 2494 nil, 2495 ), 2496 "https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042": NewAPNote( 2497 URLMustParse("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042"), 2498 URLMustParse("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042"), 2499 TimeMustParse("2022-07-13T12:13:12+02:00"), 2500 "", 2501 "", 2502 URLMustParse("https://turnip.farm/users/turniplover6969"), 2503 []*url.URL{ 2504 URLMustParse(pub.PublicActivityPubIRI), 2505 }, 2506 []*url.URL{}, 2507 false, 2508 nil, 2509 []vocab.ActivityStreamsImage{ 2510 newAPImage( 2511 URLMustParse("https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg"), 2512 "image/jpeg", 2513 "", 2514 "", 2515 ), 2516 }, 2517 ), 2518 "http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552": NewAPNote( 2519 URLMustParse("http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552"), 2520 URLMustParse("http://fossbros-anonymous.io/@foss_satan/106221634728637552"), 2521 TimeMustParse("2022-07-13T12:13:12+02:00"), 2522 `<p><span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention">@<span>the_mighty_zork</span></a></span> nice there it is:</p><p><a href="http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/activity" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">social.pixie.town/users/f0x/st</span><span class="invisible">atuses/106221628567855262/activity</span></a></p>`, 2523 "", 2524 URLMustParse("http://fossbros-anonymous.io/users/foss_satan"), 2525 []*url.URL{ 2526 URLMustParse(pub.PublicActivityPubIRI), 2527 }, 2528 []*url.URL{}, 2529 false, 2530 []vocab.ActivityStreamsMention{ 2531 newAPMention( 2532 URLMustParse("http://localhost:8080/users/the_mighty_zork"), 2533 "@the_mighty_zork@localhost:8080", 2534 ), 2535 }, 2536 nil, 2537 ), 2538 } 2539 } 2540 2541 // NewTestBookmarks returns a map of gts model bookmarks, keyed in the format [bookmarking_account]_[target_status] 2542 func NewTestBookmarks() map[string]*gtsmodel.StatusBookmark { 2543 return map[string]*gtsmodel.StatusBookmark{ 2544 "local_account_1_admin_account_status_1": { 2545 ID: "01F8MHD2QCZSZ6WQS2ATVPEYJ9", 2546 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 2547 AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 2548 TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account 2549 StatusID: "01F8MH75CBF9JFX4ZAD54N0W0R", // admin account status 1 2550 }, 2551 "admin_account_local_account_1_status_1": { 2552 ID: "01F8Q0486ANTDWKG02A7DS1Q24", 2553 CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), 2554 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", // admin account 2555 TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", // local account 1 2556 StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", // local account status 1 2557 }, 2558 } 2559 } 2560 2561 // NewTestDereferenceRequests returns a map of incoming dereference requests, with their signatures. 2562 func NewTestDereferenceRequests(accounts map[string]*gtsmodel.Account) map[string]ActivityWithSignature { 2563 var sig, digest, date string 2564 var target *url.URL 2565 statuses := NewTestStatuses() 2566 emojis := NewTestEmojis() 2567 2568 target = URLMustParse(accounts["local_account_1"].URI) 2569 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2570 fossSatanDereferenceZork := ActivityWithSignature{ 2571 SignatureHeader: sig, 2572 DigestHeader: digest, 2573 DateHeader: date, 2574 } 2575 2576 target = URLMustParse(accounts["local_account_1"].PublicKeyURI) 2577 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2578 fossSatanDereferenceZorkPublicKey := ActivityWithSignature{ 2579 SignatureHeader: sig, 2580 DigestHeader: digest, 2581 DateHeader: date, 2582 } 2583 2584 target = URLMustParse(statuses["local_account_1_status_1"].URI) 2585 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2586 fossSatanDereferenceLocalAccount1Status1 := ActivityWithSignature{ 2587 SignatureHeader: sig, 2588 DigestHeader: digest, 2589 DateHeader: date, 2590 } 2591 2592 target = URLMustParse(strings.ToLower(statuses["local_account_1_status_1"].URI)) 2593 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2594 fossSatanDereferenceLocalAccount1Status1Lowercase := ActivityWithSignature{ 2595 SignatureHeader: sig, 2596 DigestHeader: digest, 2597 DateHeader: date, 2598 } 2599 2600 target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies") 2601 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2602 fossSatanDereferenceLocalAccount1Status1Replies := ActivityWithSignature{ 2603 SignatureHeader: sig, 2604 DigestHeader: digest, 2605 DateHeader: date, 2606 } 2607 2608 target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies?only_other_accounts=false&page=true") 2609 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2610 fossSatanDereferenceLocalAccount1Status1RepliesNext := ActivityWithSignature{ 2611 SignatureHeader: sig, 2612 DigestHeader: digest, 2613 DateHeader: date, 2614 } 2615 2616 target = URLMustParse(statuses["local_account_1_status_1"].URI + "/replies?only_other_accounts=false&page=true&min_id=01FF25D5Q0DH7CHD57CTRS6WK0") 2617 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2618 fossSatanDereferenceLocalAccount1Status1RepliesLast := ActivityWithSignature{ 2619 SignatureHeader: sig, 2620 DigestHeader: digest, 2621 DateHeader: date, 2622 } 2623 2624 target = URLMustParse(accounts["local_account_1"].OutboxURI) 2625 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2626 fossSatanDereferenceZorkOutbox := ActivityWithSignature{ 2627 SignatureHeader: sig, 2628 DigestHeader: digest, 2629 DateHeader: date, 2630 } 2631 2632 target = URLMustParse(accounts["local_account_1"].OutboxURI + "?page=true") 2633 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2634 fossSatanDereferenceZorkOutboxFirst := ActivityWithSignature{ 2635 SignatureHeader: sig, 2636 DigestHeader: digest, 2637 DateHeader: date, 2638 } 2639 2640 target = URLMustParse(accounts["local_account_1"].OutboxURI + "?page=true&max_id=01F8MHAMCHF6Y650WCRSCP4WMY") 2641 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2642 fossSatanDereferenceZorkOutboxNext := ActivityWithSignature{ 2643 SignatureHeader: sig, 2644 DigestHeader: digest, 2645 DateHeader: date, 2646 } 2647 2648 target = URLMustParse(emojis["rainbow"].URI) 2649 sig, digest, date = GetSignatureForDereference(accounts["remote_account_1"].PublicKeyURI, accounts["remote_account_1"].PrivateKey, target) 2650 fossSatanDereferenceEmoji := ActivityWithSignature{ 2651 SignatureHeader: sig, 2652 DigestHeader: digest, 2653 DateHeader: date, 2654 } 2655 2656 return map[string]ActivityWithSignature{ 2657 "foss_satan_dereference_zork": fossSatanDereferenceZork, 2658 "foss_satan_dereference_zork_public_key": fossSatanDereferenceZorkPublicKey, 2659 "foss_satan_dereference_local_account_1_status_1": fossSatanDereferenceLocalAccount1Status1, 2660 "foss_satan_dereference_local_account_1_status_1_lowercase": fossSatanDereferenceLocalAccount1Status1Lowercase, 2661 "foss_satan_dereference_local_account_1_status_1_replies": fossSatanDereferenceLocalAccount1Status1Replies, 2662 "foss_satan_dereference_local_account_1_status_1_replies_next": fossSatanDereferenceLocalAccount1Status1RepliesNext, 2663 "foss_satan_dereference_local_account_1_status_1_replies_last": fossSatanDereferenceLocalAccount1Status1RepliesLast, 2664 "foss_satan_dereference_zork_outbox": fossSatanDereferenceZorkOutbox, 2665 "foss_satan_dereference_zork_outbox_first": fossSatanDereferenceZorkOutboxFirst, 2666 "foss_satan_dereference_zork_outbox_next": fossSatanDereferenceZorkOutboxNext, 2667 "foss_satan_dereference_emoji": fossSatanDereferenceEmoji, 2668 } 2669 } 2670 2671 // 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. 2672 func GetSignatureForActivity(activity pub.Activity, pubKeyID string, privkey *rsa.PrivateKey, destination *url.URL) (signatureHeader string, digestHeader string, dateHeader string) { 2673 // convert the activity into json bytes 2674 m, err := activity.Serialize() 2675 if err != nil { 2676 panic(err) 2677 } 2678 b, err := json.Marshal(m) 2679 if err != nil { 2680 panic(err) 2681 } 2682 2683 // Prepare HTTP request signer 2684 sig, err := transport.NewPOSTSigner(120) 2685 if err != nil { 2686 panic(err) 2687 } 2688 2689 // Prepare a mock request ready for signing 2690 r, err := http.NewRequest("POST", destination.String(), bytes.NewReader(b)) 2691 if err != nil { 2692 panic(err) 2693 } 2694 r.Header.Set("Host", destination.Host) 2695 r.Header.Set("Date", time.Now().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") 2696 2697 // Sign this new HTTP request 2698 if err := sig.SignRequest(privkey, pubKeyID, r, b); err != nil { 2699 panic(err) 2700 } 2701 2702 // Load signed data from request 2703 signatureHeader = r.Header.Get("Signature") 2704 digestHeader = r.Header.Get("Digest") 2705 dateHeader = r.Header.Get("Date") 2706 2707 // headers should now be populated 2708 return 2709 } 2710 2711 // 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. 2712 func GetSignatureForDereference(pubKeyID string, privkey *rsa.PrivateKey, destination *url.URL) (signatureHeader string, digestHeader string, dateHeader string) { 2713 // Prepare HTTP request signer 2714 sig, err := transport.NewGETSigner(120) 2715 if err != nil { 2716 panic(err) 2717 } 2718 2719 // Prepare a mock request ready for signing 2720 r, err := http.NewRequest("GET", destination.String(), nil) 2721 if err != nil { 2722 panic(err) 2723 } 2724 r.Header.Set("Host", destination.Host) 2725 r.Header.Set("Date", time.Now().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") 2726 2727 // Sign this new HTTP request 2728 if err := sig.SignRequest(privkey, pubKeyID, r, nil); err != nil { 2729 panic(err) 2730 } 2731 2732 // Load signed data from request 2733 signatureHeader = r.Header.Get("Signature") 2734 digestHeader = r.Header.Get("Digest") 2735 dateHeader = r.Header.Get("Date") 2736 2737 // headers should now be populated 2738 return 2739 } 2740 2741 func newAPPerson( 2742 profileIDURI *url.URL, 2743 followingURI *url.URL, 2744 followersURI *url.URL, 2745 inboxURI *url.URL, 2746 sharedInboxIRI *url.URL, 2747 outboxURI *url.URL, 2748 featuredURI *url.URL, 2749 username string, 2750 displayName string, 2751 note string, 2752 profileURL *url.URL, 2753 discoverable bool, 2754 publicKeyURI *url.URL, 2755 pkey *rsa.PublicKey, 2756 avatarURL *url.URL, 2757 avatarContentType string, 2758 headerURL *url.URL, 2759 headerContentType string, 2760 manuallyApprovesFollowers bool, 2761 ) vocab.ActivityStreamsPerson { 2762 person := streams.NewActivityStreamsPerson() 2763 2764 // id should be the activitypub URI of this user 2765 // something like https://example.org/users/example_user 2766 idProp := streams.NewJSONLDIdProperty() 2767 idProp.SetIRI(profileIDURI) 2768 person.SetJSONLDId(idProp) 2769 2770 // following 2771 // The URI for retrieving a list of accounts this user is following 2772 followingProp := streams.NewActivityStreamsFollowingProperty() 2773 followingProp.SetIRI(followingURI) 2774 person.SetActivityStreamsFollowing(followingProp) 2775 2776 // followers 2777 // The URI for retrieving a list of this user's followers 2778 followersProp := streams.NewActivityStreamsFollowersProperty() 2779 followersProp.SetIRI(followersURI) 2780 person.SetActivityStreamsFollowers(followersProp) 2781 2782 // inbox 2783 // the activitypub inbox of this user for accepting messages 2784 inboxProp := streams.NewActivityStreamsInboxProperty() 2785 inboxProp.SetIRI(inboxURI) 2786 person.SetActivityStreamsInbox(inboxProp) 2787 2788 // shared inbox 2789 if sharedInboxIRI != nil { 2790 endpointsProp := streams.NewActivityStreamsEndpointsProperty() 2791 endpoints := streams.NewActivityStreamsEndpoints() 2792 sharedInboxProp := streams.NewActivityStreamsSharedInboxProperty() 2793 sharedInboxProp.SetIRI(sharedInboxIRI) 2794 endpoints.SetActivityStreamsSharedInbox(sharedInboxProp) 2795 endpointsProp.AppendActivityStreamsEndpoints(endpoints) 2796 person.SetActivityStreamsEndpoints(endpointsProp) 2797 } 2798 2799 // outbox 2800 // the activitypub outbox of this user for serving messages 2801 outboxProp := streams.NewActivityStreamsOutboxProperty() 2802 outboxProp.SetIRI(outboxURI) 2803 person.SetActivityStreamsOutbox(outboxProp) 2804 2805 // featured posts 2806 // Pinned posts. 2807 featuredProp := streams.NewTootFeaturedProperty() 2808 featuredProp.SetIRI(featuredURI) 2809 person.SetTootFeatured(featuredProp) 2810 2811 // featuredTags 2812 // NOT IMPLEMENTED 2813 2814 // preferredUsername 2815 // Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. 2816 preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() 2817 preferredUsernameProp.SetXMLSchemaString(username) 2818 person.SetActivityStreamsPreferredUsername(preferredUsernameProp) 2819 2820 // name 2821 // Used as profile display name. 2822 nameProp := streams.NewActivityStreamsNameProperty() 2823 if displayName != "" { 2824 nameProp.AppendXMLSchemaString(displayName) 2825 } else { 2826 nameProp.AppendXMLSchemaString(username) 2827 } 2828 person.SetActivityStreamsName(nameProp) 2829 2830 // summary 2831 // Used as profile bio. 2832 if note != "" { 2833 summaryProp := streams.NewActivityStreamsSummaryProperty() 2834 summaryProp.AppendXMLSchemaString(note) 2835 person.SetActivityStreamsSummary(summaryProp) 2836 } 2837 2838 // url 2839 // Used as profile link. 2840 urlProp := streams.NewActivityStreamsUrlProperty() 2841 urlProp.AppendIRI(profileURL) 2842 person.SetActivityStreamsUrl(urlProp) 2843 2844 // manuallyApprovesFollowers 2845 manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() 2846 manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers) 2847 person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) 2848 2849 // discoverable 2850 // Will be shown in the profile directory. 2851 discoverableProp := streams.NewTootDiscoverableProperty() 2852 discoverableProp.Set(discoverable) 2853 person.SetTootDiscoverable(discoverableProp) 2854 2855 // devices 2856 // NOT IMPLEMENTED, probably won't implement 2857 2858 // alsoKnownAs 2859 // Required for Move activity. 2860 // 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 2861 2862 // publicKey 2863 // Required for signatures. 2864 publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty() 2865 2866 // create the public key 2867 publicKey := streams.NewW3IDSecurityV1PublicKey() 2868 2869 // set ID for the public key 2870 publicKeyIDProp := streams.NewJSONLDIdProperty() 2871 publicKeyIDProp.SetIRI(publicKeyURI) 2872 publicKey.SetJSONLDId(publicKeyIDProp) 2873 2874 // set owner for the public key 2875 publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty() 2876 publicKeyOwnerProp.SetIRI(profileIDURI) 2877 publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp) 2878 2879 // set the pem key itself 2880 encodedPublicKey, err := x509.MarshalPKIXPublicKey(pkey) 2881 if err != nil { 2882 panic(err) 2883 } 2884 publicKeyBytes := pem.EncodeToMemory(&pem.Block{ 2885 Type: "PUBLIC KEY", 2886 Bytes: encodedPublicKey, 2887 }) 2888 publicKeyPEMProp := streams.NewW3IDSecurityV1PublicKeyPemProperty() 2889 publicKeyPEMProp.Set(string(publicKeyBytes)) 2890 publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp) 2891 2892 // append the public key to the public key property 2893 publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) 2894 2895 // set the public key property on the Person 2896 person.SetW3IDSecurityV1PublicKey(publicKeyProp) 2897 2898 // tag 2899 // TODO: Any tags used in the summary of this profile 2900 2901 // attachment 2902 // Used for profile fields. 2903 // TODO: The PropertyValue type has to be added: https://schema.org/PropertyValue 2904 2905 // endpoints 2906 // NOT IMPLEMENTED -- this is for shared inbox which we don't use 2907 2908 // icon 2909 // Used as profile avatar. 2910 iconProperty := streams.NewActivityStreamsIconProperty() 2911 iconImage := streams.NewActivityStreamsImage() 2912 mediaType := streams.NewActivityStreamsMediaTypeProperty() 2913 mediaType.Set(avatarContentType) 2914 iconImage.SetActivityStreamsMediaType(mediaType) 2915 avatarURLProperty := streams.NewActivityStreamsUrlProperty() 2916 avatarURLProperty.AppendIRI(avatarURL) 2917 iconImage.SetActivityStreamsUrl(avatarURLProperty) 2918 iconProperty.AppendActivityStreamsImage(iconImage) 2919 person.SetActivityStreamsIcon(iconProperty) 2920 2921 // image 2922 // Used as profile header. 2923 headerProperty := streams.NewActivityStreamsImageProperty() 2924 headerImage := streams.NewActivityStreamsImage() 2925 headerMediaType := streams.NewActivityStreamsMediaTypeProperty() 2926 mediaType.Set(headerContentType) 2927 headerImage.SetActivityStreamsMediaType(headerMediaType) 2928 headerURLProperty := streams.NewActivityStreamsUrlProperty() 2929 headerURLProperty.AppendIRI(headerURL) 2930 headerImage.SetActivityStreamsUrl(headerURLProperty) 2931 headerProperty.AppendActivityStreamsImage(headerImage) 2932 person.SetActivityStreamsImage(headerProperty) 2933 2934 return person 2935 } 2936 2937 func newAPGroup( 2938 profileIDURI *url.URL, 2939 followingURI *url.URL, 2940 followersURI *url.URL, 2941 inboxURI *url.URL, 2942 outboxURI *url.URL, 2943 featuredURI *url.URL, 2944 username string, 2945 displayName string, 2946 note string, 2947 profileURL *url.URL, 2948 discoverable bool, 2949 publicKeyURI *url.URL, 2950 pkey *rsa.PublicKey, 2951 avatarURL *url.URL, 2952 avatarContentType string, 2953 headerURL *url.URL, 2954 headerContentType string, 2955 manuallyApprovesFollowers bool, 2956 ) vocab.ActivityStreamsGroup { 2957 group := streams.NewActivityStreamsGroup() 2958 2959 // id should be the activitypub URI of this group 2960 // something like https://example.org/users/example_group 2961 idProp := streams.NewJSONLDIdProperty() 2962 idProp.SetIRI(profileIDURI) 2963 group.SetJSONLDId(idProp) 2964 2965 // following 2966 // The URI for retrieving a list of accounts this group is following 2967 followingProp := streams.NewActivityStreamsFollowingProperty() 2968 followingProp.SetIRI(followingURI) 2969 group.SetActivityStreamsFollowing(followingProp) 2970 2971 // followers 2972 // The URI for retrieving a list of this user's followers 2973 followersProp := streams.NewActivityStreamsFollowersProperty() 2974 followersProp.SetIRI(followersURI) 2975 group.SetActivityStreamsFollowers(followersProp) 2976 2977 // inbox 2978 // the activitypub inbox of this user for accepting messages 2979 inboxProp := streams.NewActivityStreamsInboxProperty() 2980 inboxProp.SetIRI(inboxURI) 2981 group.SetActivityStreamsInbox(inboxProp) 2982 2983 // outbox 2984 // the activitypub outbox of this user for serving messages 2985 outboxProp := streams.NewActivityStreamsOutboxProperty() 2986 outboxProp.SetIRI(outboxURI) 2987 group.SetActivityStreamsOutbox(outboxProp) 2988 2989 // featured posts 2990 // Pinned posts. 2991 featuredProp := streams.NewTootFeaturedProperty() 2992 featuredProp.SetIRI(featuredURI) 2993 group.SetTootFeatured(featuredProp) 2994 2995 // featuredTags 2996 // NOT IMPLEMENTED 2997 2998 // preferredUsername 2999 // Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. 3000 preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() 3001 preferredUsernameProp.SetXMLSchemaString(username) 3002 group.SetActivityStreamsPreferredUsername(preferredUsernameProp) 3003 3004 // name 3005 // Used as profile display name. 3006 nameProp := streams.NewActivityStreamsNameProperty() 3007 if displayName != "" { 3008 nameProp.AppendXMLSchemaString(displayName) 3009 } else { 3010 nameProp.AppendXMLSchemaString(username) 3011 } 3012 group.SetActivityStreamsName(nameProp) 3013 3014 // summary 3015 // Used as profile bio. 3016 if note != "" { 3017 summaryProp := streams.NewActivityStreamsSummaryProperty() 3018 summaryProp.AppendXMLSchemaString(note) 3019 group.SetActivityStreamsSummary(summaryProp) 3020 } 3021 3022 // url 3023 // Used as profile link. 3024 urlProp := streams.NewActivityStreamsUrlProperty() 3025 urlProp.AppendIRI(profileURL) 3026 group.SetActivityStreamsUrl(urlProp) 3027 3028 // manuallyApprovesFollowers 3029 manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() 3030 manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers) 3031 group.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) 3032 3033 // discoverable 3034 // Will be shown in the profile directory. 3035 discoverableProp := streams.NewTootDiscoverableProperty() 3036 discoverableProp.Set(discoverable) 3037 group.SetTootDiscoverable(discoverableProp) 3038 3039 // devices 3040 // NOT IMPLEMENTED, probably won't implement 3041 3042 // alsoKnownAs 3043 // Required for Move activity. 3044 // 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 3045 3046 // publicKey 3047 // Required for signatures. 3048 publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty() 3049 3050 // create the public key 3051 publicKey := streams.NewW3IDSecurityV1PublicKey() 3052 3053 // set ID for the public key 3054 publicKeyIDProp := streams.NewJSONLDIdProperty() 3055 publicKeyIDProp.SetIRI(publicKeyURI) 3056 publicKey.SetJSONLDId(publicKeyIDProp) 3057 3058 // set owner for the public key 3059 publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty() 3060 publicKeyOwnerProp.SetIRI(profileIDURI) 3061 publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp) 3062 3063 // set the pem key itself 3064 encodedPublicKey, err := x509.MarshalPKIXPublicKey(pkey) 3065 if err != nil { 3066 panic(err) 3067 } 3068 publicKeyBytes := pem.EncodeToMemory(&pem.Block{ 3069 Type: "PUBLIC KEY", 3070 Bytes: encodedPublicKey, 3071 }) 3072 publicKeyPEMProp := streams.NewW3IDSecurityV1PublicKeyPemProperty() 3073 publicKeyPEMProp.Set(string(publicKeyBytes)) 3074 publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp) 3075 3076 // append the public key to the public key property 3077 publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) 3078 3079 // set the public key property on the Person 3080 group.SetW3IDSecurityV1PublicKey(publicKeyProp) 3081 3082 // tag 3083 // TODO: Any tags used in the summary of this profile 3084 3085 // attachment 3086 // Used for profile fields. 3087 // TODO: The PropertyValue type has to be added: https://schema.org/PropertyValue 3088 3089 // endpoints 3090 // NOT IMPLEMENTED -- this is for shared inbox which we don't use 3091 3092 // icon 3093 // Used as profile avatar. 3094 iconProperty := streams.NewActivityStreamsIconProperty() 3095 iconImage := streams.NewActivityStreamsImage() 3096 mediaType := streams.NewActivityStreamsMediaTypeProperty() 3097 mediaType.Set(avatarContentType) 3098 iconImage.SetActivityStreamsMediaType(mediaType) 3099 avatarURLProperty := streams.NewActivityStreamsUrlProperty() 3100 avatarURLProperty.AppendIRI(avatarURL) 3101 iconImage.SetActivityStreamsUrl(avatarURLProperty) 3102 iconProperty.AppendActivityStreamsImage(iconImage) 3103 group.SetActivityStreamsIcon(iconProperty) 3104 3105 // image 3106 // Used as profile header. 3107 headerProperty := streams.NewActivityStreamsImageProperty() 3108 headerImage := streams.NewActivityStreamsImage() 3109 headerMediaType := streams.NewActivityStreamsMediaTypeProperty() 3110 mediaType.Set(headerContentType) 3111 headerImage.SetActivityStreamsMediaType(headerMediaType) 3112 headerURLProperty := streams.NewActivityStreamsUrlProperty() 3113 headerURLProperty.AppendIRI(headerURL) 3114 headerImage.SetActivityStreamsUrl(headerURLProperty) 3115 headerProperty.AppendActivityStreamsImage(headerImage) 3116 group.SetActivityStreamsImage(headerProperty) 3117 3118 return group 3119 } 3120 3121 func newAPService( 3122 profileIDURI *url.URL, 3123 followingURI *url.URL, 3124 followersURI *url.URL, 3125 inboxURI *url.URL, 3126 outboxURI *url.URL, 3127 featuredURI *url.URL, 3128 username string, 3129 displayName string, 3130 note string, 3131 profileURL *url.URL, 3132 discoverable bool, 3133 publicKeyURI *url.URL, 3134 pkey *rsa.PublicKey, 3135 avatarURL *url.URL, 3136 avatarContentType string, 3137 headerURL *url.URL, 3138 headerContentType string, 3139 manuallyApprovesFollowers bool, 3140 ) vocab.ActivityStreamsService { 3141 service := streams.NewActivityStreamsService() 3142 3143 // id should be the activitypub URI of this group 3144 // something like https://example.org/users/example_group 3145 idProp := streams.NewJSONLDIdProperty() 3146 idProp.SetIRI(profileIDURI) 3147 service.SetJSONLDId(idProp) 3148 3149 // following 3150 // The URI for retrieving a list of accounts this group is following 3151 followingProp := streams.NewActivityStreamsFollowingProperty() 3152 followingProp.SetIRI(followingURI) 3153 service.SetActivityStreamsFollowing(followingProp) 3154 3155 // followers 3156 // The URI for retrieving a list of this user's followers 3157 followersProp := streams.NewActivityStreamsFollowersProperty() 3158 followersProp.SetIRI(followersURI) 3159 service.SetActivityStreamsFollowers(followersProp) 3160 3161 // inbox 3162 // the activitypub inbox of this user for accepting messages 3163 inboxProp := streams.NewActivityStreamsInboxProperty() 3164 inboxProp.SetIRI(inboxURI) 3165 service.SetActivityStreamsInbox(inboxProp) 3166 3167 // outbox 3168 // the activitypub outbox of this user for serving messages 3169 outboxProp := streams.NewActivityStreamsOutboxProperty() 3170 outboxProp.SetIRI(outboxURI) 3171 service.SetActivityStreamsOutbox(outboxProp) 3172 3173 // featured posts 3174 // Pinned posts. 3175 featuredProp := streams.NewTootFeaturedProperty() 3176 featuredProp.SetIRI(featuredURI) 3177 service.SetTootFeatured(featuredProp) 3178 3179 // featuredTags 3180 // NOT IMPLEMENTED 3181 3182 // preferredUsername 3183 // Used for Webfinger lookup. Must be unique on the domain, and must correspond to a Webfinger acct: URI. 3184 preferredUsernameProp := streams.NewActivityStreamsPreferredUsernameProperty() 3185 preferredUsernameProp.SetXMLSchemaString(username) 3186 service.SetActivityStreamsPreferredUsername(preferredUsernameProp) 3187 3188 // name 3189 // Used as profile display name. 3190 nameProp := streams.NewActivityStreamsNameProperty() 3191 if displayName != "" { 3192 nameProp.AppendXMLSchemaString(displayName) 3193 } else { 3194 nameProp.AppendXMLSchemaString(username) 3195 } 3196 service.SetActivityStreamsName(nameProp) 3197 3198 // summary 3199 // Used as profile bio. 3200 if note != "" { 3201 summaryProp := streams.NewActivityStreamsSummaryProperty() 3202 summaryProp.AppendXMLSchemaString(note) 3203 service.SetActivityStreamsSummary(summaryProp) 3204 } 3205 3206 // url 3207 // Used as profile link. 3208 urlProp := streams.NewActivityStreamsUrlProperty() 3209 urlProp.AppendIRI(profileURL) 3210 service.SetActivityStreamsUrl(urlProp) 3211 3212 // manuallyApprovesFollowers 3213 manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() 3214 manuallyApprovesFollowersProp.Set(manuallyApprovesFollowers) 3215 service.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) 3216 3217 // discoverable 3218 // Will be shown in the profile directory. 3219 discoverableProp := streams.NewTootDiscoverableProperty() 3220 discoverableProp.Set(discoverable) 3221 service.SetTootDiscoverable(discoverableProp) 3222 3223 // devices 3224 // NOT IMPLEMENTED, probably won't implement 3225 3226 // alsoKnownAs 3227 // Required for Move activity. 3228 // 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 3229 3230 // publicKey 3231 // Required for signatures. 3232 publicKeyProp := streams.NewW3IDSecurityV1PublicKeyProperty() 3233 3234 // create the public key 3235 publicKey := streams.NewW3IDSecurityV1PublicKey() 3236 3237 // set ID for the public key 3238 publicKeyIDProp := streams.NewJSONLDIdProperty() 3239 publicKeyIDProp.SetIRI(publicKeyURI) 3240 publicKey.SetJSONLDId(publicKeyIDProp) 3241 3242 // set owner for the public key 3243 publicKeyOwnerProp := streams.NewW3IDSecurityV1OwnerProperty() 3244 publicKeyOwnerProp.SetIRI(profileIDURI) 3245 publicKey.SetW3IDSecurityV1Owner(publicKeyOwnerProp) 3246 3247 // set the pem key itself 3248 encodedPublicKey, err := x509.MarshalPKIXPublicKey(pkey) 3249 if err != nil { 3250 panic(err) 3251 } 3252 publicKeyBytes := pem.EncodeToMemory(&pem.Block{ 3253 Type: "PUBLIC KEY", 3254 Bytes: encodedPublicKey, 3255 }) 3256 publicKeyPEMProp := streams.NewW3IDSecurityV1PublicKeyPemProperty() 3257 publicKeyPEMProp.Set(string(publicKeyBytes)) 3258 publicKey.SetW3IDSecurityV1PublicKeyPem(publicKeyPEMProp) 3259 3260 // append the public key to the public key property 3261 publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKey) 3262 3263 // set the public key property on the Person 3264 service.SetW3IDSecurityV1PublicKey(publicKeyProp) 3265 3266 // tag 3267 // TODO: Any tags used in the summary of this profile 3268 3269 // attachment 3270 // Used for profile fields. 3271 // TODO: The PropertyValue type has to be added: https://schema.org/PropertyValue 3272 3273 // endpoints 3274 // NOT IMPLEMENTED -- this is for shared inbox which we don't use 3275 3276 // icon 3277 // Used as profile avatar. 3278 iconProperty := streams.NewActivityStreamsIconProperty() 3279 iconImage := streams.NewActivityStreamsImage() 3280 mediaType := streams.NewActivityStreamsMediaTypeProperty() 3281 mediaType.Set(avatarContentType) 3282 iconImage.SetActivityStreamsMediaType(mediaType) 3283 avatarURLProperty := streams.NewActivityStreamsUrlProperty() 3284 avatarURLProperty.AppendIRI(avatarURL) 3285 iconImage.SetActivityStreamsUrl(avatarURLProperty) 3286 iconProperty.AppendActivityStreamsImage(iconImage) 3287 service.SetActivityStreamsIcon(iconProperty) 3288 3289 // image 3290 // Used as profile header. 3291 headerProperty := streams.NewActivityStreamsImageProperty() 3292 headerImage := streams.NewActivityStreamsImage() 3293 headerMediaType := streams.NewActivityStreamsMediaTypeProperty() 3294 mediaType.Set(headerContentType) 3295 headerImage.SetActivityStreamsMediaType(headerMediaType) 3296 headerURLProperty := streams.NewActivityStreamsUrlProperty() 3297 headerURLProperty.AppendIRI(headerURL) 3298 headerImage.SetActivityStreamsUrl(headerURLProperty) 3299 headerProperty.AppendActivityStreamsImage(headerImage) 3300 service.SetActivityStreamsImage(headerProperty) 3301 3302 return service 3303 } 3304 3305 func newAPMention(uri *url.URL, namestring string) vocab.ActivityStreamsMention { 3306 mention := streams.NewActivityStreamsMention() 3307 3308 hrefProp := streams.NewActivityStreamsHrefProperty() 3309 hrefProp.SetIRI(uri) 3310 mention.SetActivityStreamsHref(hrefProp) 3311 3312 nameProp := streams.NewActivityStreamsNameProperty() 3313 nameProp.AppendXMLSchemaString(namestring) 3314 mention.SetActivityStreamsName(nameProp) 3315 3316 return mention 3317 } 3318 3319 func newAPImage(url *url.URL, mediaType string, imageDescription string, blurhash string) vocab.ActivityStreamsImage { 3320 image := streams.NewActivityStreamsImage() 3321 3322 if url != nil { 3323 urlProp := streams.NewActivityStreamsUrlProperty() 3324 urlProp.AppendIRI(url) 3325 image.SetActivityStreamsUrl(urlProp) 3326 } 3327 3328 if mediaType != "" { 3329 mediaTypeProp := streams.NewActivityStreamsMediaTypeProperty() 3330 mediaTypeProp.Set(mediaType) 3331 image.SetActivityStreamsMediaType(mediaTypeProp) 3332 } 3333 3334 if imageDescription != "" { 3335 nameProp := streams.NewActivityStreamsNameProperty() 3336 nameProp.AppendXMLSchemaString(imageDescription) 3337 image.SetActivityStreamsName(nameProp) 3338 } 3339 3340 if blurhash != "" { 3341 blurhashProp := streams.NewTootBlurhashProperty() 3342 blurhashProp.Set(blurhash) 3343 image.SetTootBlurhash(blurhashProp) 3344 } 3345 3346 return image 3347 } 3348 3349 func newAPEmoji(id *url.URL, name string, updated time.Time, image vocab.ActivityStreamsImage) vocab.TootEmoji { 3350 emoji := streams.NewTootEmoji() 3351 3352 idProp := streams.NewJSONLDIdProperty() 3353 idProp.SetIRI(id) 3354 emoji.SetJSONLDId(idProp) 3355 3356 nameProp := streams.NewActivityStreamsNameProperty() 3357 nameProp.AppendXMLSchemaString(`:` + strings.Trim(name, ":") + `:`) 3358 emoji.SetActivityStreamsName(nameProp) 3359 3360 updatedProp := streams.NewActivityStreamsUpdatedProperty() 3361 updatedProp.Set(updated) 3362 emoji.SetActivityStreamsUpdated(updatedProp) 3363 3364 iconProp := streams.NewActivityStreamsIconProperty() 3365 iconProp.AppendActivityStreamsImage(image) 3366 emoji.SetActivityStreamsIcon(iconProp) 3367 3368 return emoji 3369 } 3370 3371 // NewAPNote returns a new activity streams note for the given parameters 3372 func NewAPNote( 3373 noteID *url.URL, 3374 noteURL *url.URL, 3375 noteCreatedAt time.Time, 3376 noteContent string, 3377 noteSummary string, 3378 noteAttributedTo *url.URL, 3379 noteTo []*url.URL, 3380 noteCC []*url.URL, 3381 noteSensitive bool, 3382 noteMentions []vocab.ActivityStreamsMention, 3383 noteAttachments []vocab.ActivityStreamsImage, 3384 ) vocab.ActivityStreamsNote { 3385 // create the note itself 3386 note := streams.NewActivityStreamsNote() 3387 3388 // set id 3389 if noteID != nil { 3390 id := streams.NewJSONLDIdProperty() 3391 id.Set(noteID) 3392 note.SetJSONLDId(id) 3393 } 3394 3395 // set noteURL 3396 if noteURL != nil { 3397 url := streams.NewActivityStreamsUrlProperty() 3398 url.AppendIRI(noteURL) 3399 note.SetActivityStreamsUrl(url) 3400 } 3401 3402 published := streams.NewActivityStreamsPublishedProperty() 3403 published.Set(noteCreatedAt) 3404 note.SetActivityStreamsPublished(published) 3405 3406 // set noteContent 3407 if noteContent != "" { 3408 content := streams.NewActivityStreamsContentProperty() 3409 content.AppendXMLSchemaString(noteContent) 3410 note.SetActivityStreamsContent(content) 3411 } 3412 3413 // set noteSummary (aka content warning) 3414 if noteSummary != "" { 3415 summary := streams.NewActivityStreamsSummaryProperty() 3416 summary.AppendXMLSchemaString(noteSummary) 3417 note.SetActivityStreamsSummary(summary) 3418 } 3419 3420 // set noteAttributedTo (the url of the author of the note) 3421 if noteAttributedTo != nil { 3422 attributedTo := streams.NewActivityStreamsAttributedToProperty() 3423 attributedTo.AppendIRI(noteAttributedTo) 3424 note.SetActivityStreamsAttributedTo(attributedTo) 3425 } 3426 3427 // set noteTO 3428 if noteTo != nil { 3429 to := streams.NewActivityStreamsToProperty() 3430 for _, r := range noteTo { 3431 to.AppendIRI(r) 3432 } 3433 note.SetActivityStreamsTo(to) 3434 } 3435 3436 // set noteCC 3437 if noteCC != nil { 3438 cc := streams.NewActivityStreamsCcProperty() 3439 for _, r := range noteCC { 3440 cc.AppendIRI(r) 3441 } 3442 note.SetActivityStreamsCc(cc) 3443 } 3444 3445 // mentions 3446 tag := streams.NewActivityStreamsTagProperty() 3447 for _, m := range noteMentions { 3448 tag.AppendActivityStreamsMention(m) 3449 } 3450 note.SetActivityStreamsTag(tag) 3451 3452 // append any attachments as ActivityStreamsImage 3453 if noteAttachments != nil { 3454 attachmentProperty := streams.NewActivityStreamsAttachmentProperty() 3455 for _, a := range noteAttachments { 3456 attachmentProperty.AppendActivityStreamsImage(a) 3457 } 3458 note.SetActivityStreamsAttachment(attachmentProperty) 3459 } 3460 3461 return note 3462 } 3463 3464 // WrapAPNoteInCreate wraps the given activity streams note in a Create activity streams action 3465 func WrapAPNoteInCreate(createID *url.URL, createActor *url.URL, createPublished time.Time, createNote vocab.ActivityStreamsNote) vocab.ActivityStreamsCreate { 3466 // create the.... create 3467 create := streams.NewActivityStreamsCreate() 3468 3469 // set createID 3470 if createID != nil { 3471 id := streams.NewJSONLDIdProperty() 3472 id.Set(createID) 3473 create.SetJSONLDId(id) 3474 } 3475 3476 // set createActor 3477 if createActor != nil { 3478 actor := streams.NewActivityStreamsActorProperty() 3479 actor.AppendIRI(createActor) 3480 create.SetActivityStreamsActor(actor) 3481 } 3482 3483 // set createPublished (time) 3484 if !createPublished.IsZero() { 3485 published := streams.NewActivityStreamsPublishedProperty() 3486 published.Set(createPublished) 3487 create.SetActivityStreamsPublished(published) 3488 } 3489 3490 // setCreateTo 3491 if createNote.GetActivityStreamsTo() != nil { 3492 create.SetActivityStreamsTo(createNote.GetActivityStreamsTo()) 3493 } 3494 3495 // setCreateCC 3496 if createNote.GetActivityStreamsCc() != nil { 3497 create.SetActivityStreamsCc(createNote.GetActivityStreamsCc()) 3498 } 3499 3500 // set createNote 3501 if createNote != nil { 3502 note := streams.NewActivityStreamsObjectProperty() 3503 note.AppendActivityStreamsNote(createNote) 3504 create.SetActivityStreamsObject(note) 3505 } 3506 3507 return create 3508 } 3509 3510 func newAPAnnounce(announceID *url.URL, announceActor *url.URL, announcePublished time.Time, announceTo *url.URL, announceNote vocab.ActivityStreamsNote) vocab.ActivityStreamsAnnounce { 3511 announce := streams.NewActivityStreamsAnnounce() 3512 3513 if announceID != nil { 3514 id := streams.NewJSONLDIdProperty() 3515 id.Set(announceID) 3516 announce.SetJSONLDId(id) 3517 } 3518 3519 if announceActor != nil { 3520 actor := streams.NewActivityStreamsActorProperty() 3521 actor.AppendIRI(announceActor) 3522 announce.SetActivityStreamsActor(actor) 3523 } 3524 3525 if !announcePublished.IsZero() { 3526 published := streams.NewActivityStreamsPublishedProperty() 3527 published.Set(announcePublished) 3528 announce.SetActivityStreamsPublished(published) 3529 } 3530 3531 to := streams.NewActivityStreamsToProperty() 3532 to.AppendIRI(announceTo) 3533 announce.SetActivityStreamsTo(announceNote.GetActivityStreamsTo()) 3534 3535 cc := streams.NewActivityStreamsCcProperty() 3536 cc.AppendIRI(announceNote.GetActivityStreamsAttributedTo().Begin().GetIRI()) 3537 announce.SetActivityStreamsCc(cc) 3538 3539 if announceNote != nil { 3540 noteIRI := streams.NewActivityStreamsObjectProperty() 3541 noteIRI.AppendIRI(announceNote.GetJSONLDId().Get()) 3542 announce.SetActivityStreamsObject(noteIRI) 3543 } 3544 3545 return announce 3546 } 3547 3548 func newAPDelete(deleteTarget *url.URL, deleteActor *url.URL, deletePublished time.Time, deleteTo *url.URL) vocab.ActivityStreamsDelete { 3549 delete := streams.NewActivityStreamsDelete() 3550 3551 objectProp := streams.NewActivityStreamsObjectProperty() 3552 objectProp.AppendIRI(deleteTarget) 3553 delete.SetActivityStreamsObject(objectProp) 3554 3555 to := streams.NewActivityStreamsToProperty() 3556 to.AppendIRI(deleteTo) 3557 delete.SetActivityStreamsTo(to) 3558 3559 actor := streams.NewActivityStreamsActorProperty() 3560 actor.AppendIRI(deleteActor) 3561 delete.SetActivityStreamsActor(actor) 3562 3563 published := streams.NewActivityStreamsPublishedProperty() 3564 published.Set(deletePublished) 3565 delete.SetActivityStreamsPublished(published) 3566 3567 return delete 3568 }