Merge branch 'develop' into paradedb-search-backend
This commit is contained in:
commit
3c916891f6
39 changed files with 1782 additions and 103 deletions
32
test/fixtures/fedidev.fun/attachment_embedded_note.json
vendored
Normal file
32
test/fixtures/fedidev.fun/attachment_embedded_note.json
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/attachment-embedded-note",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:01Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-attachment-embedded-note",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:01Z",
|
||||
"content": "Note with embedded Note attachment",
|
||||
"attachment": {
|
||||
"type": "Note",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"name": "attached note",
|
||||
"content": "This is just a note",
|
||||
"published": "2024-03-06T07:23:56Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
test/fixtures/fedidev.fun/attachment_payto_link.json
vendored
Normal file
31
test/fixtures/fedidev.fun/attachment_payto_link.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/attachment-payto-link",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:00Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-attachment-payto-link",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:00Z",
|
||||
"content": "Payment Link",
|
||||
"attachment": {
|
||||
"type": "Link",
|
||||
"name": "Donate",
|
||||
"href": "payto://iban/DE75512108001245126199",
|
||||
"rel": "payment"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
test/fixtures/fedidev.fun/attachment_url_list.json
vendored
Normal file
40
test/fixtures/fedidev.fun/attachment_url_list.json
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/attachment-url-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:02Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-attachment-url-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:02Z",
|
||||
"content": "url is array of two Link objects",
|
||||
"attachment": {
|
||||
"type": "Image",
|
||||
"url": [
|
||||
{
|
||||
"type": "Link",
|
||||
"href": "https://fedidev.fun/images/007.png",
|
||||
"mediaType": "image/png"
|
||||
},
|
||||
{
|
||||
"type": "Link",
|
||||
"href": "https://fedidev.fun/images/008.jpg",
|
||||
"mediaType": "image/jpeg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
test/fixtures/fedidev.fun/emoji_icon_string.json
vendored
Normal file
32
test/fixtures/fedidev.fun/emoji_icon_string.json
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/emoji-icon-string",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:00Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-emoji-icon-string",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:00Z",
|
||||
"content": "emoji icon as string :cow:",
|
||||
"tag": [
|
||||
{
|
||||
"type": "Emoji",
|
||||
"name": ":cow:",
|
||||
"icon": "https://fedidev.fun/static/cow.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
34
test/fixtures/fedidev.fun/emoji_icon_url_missing_type.json
vendored
Normal file
34
test/fixtures/fedidev.fun/emoji_icon_url_missing_type.json
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/emoji-icon-url-missing-type",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:01Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-emoji-icon-url-missing-type",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:01Z",
|
||||
"content": "emoji icon url missing type :cow2:",
|
||||
"tag": [
|
||||
{
|
||||
"type": "Emoji",
|
||||
"name": ":cow2:",
|
||||
"icon": {
|
||||
"url": "https://fedidev.fun/static/cow.png"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
31
test/fixtures/fedidev.fun/emoji_missing_icon.json
vendored
Normal file
31
test/fixtures/fedidev.fun/emoji_missing_icon.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/emoji-missing-icon",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:02Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-emoji-missing-icon",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:02Z",
|
||||
"content": "emoji missing icon :cow3:",
|
||||
"tag": [
|
||||
{
|
||||
"type": "Emoji",
|
||||
"name": ":cow3:"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
30
test/fixtures/fedidev.fun/in_reply_to_collection.json
vendored
Normal file
30
test/fixtures/fedidev.fun/in_reply_to_collection.json
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/in-reply-to-collection",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:08Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-in-reply-to-collection",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:08Z",
|
||||
"content": "collection",
|
||||
"inReplyTo": {
|
||||
"type": "Collection",
|
||||
"items": [
|
||||
"https://fedidev.fun/users/alice"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
35
test/fixtures/fedidev.fun/in_reply_to_embedded_note.json
vendored
Normal file
35
test/fixtures/fedidev.fun/in_reply_to_embedded_note.json
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/in-reply-to-embedded-note",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:21Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-in-reply-to-embedded-note",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:21Z",
|
||||
"content": "embedded note",
|
||||
"inReplyTo": {
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/assets/note1.jsonap",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"content": "One",
|
||||
"published": "2024-01-06T13:11:45Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
28
test/fixtures/fedidev.fun/in_reply_to_link.json
vendored
Normal file
28
test/fixtures/fedidev.fun/in_reply_to_link.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/in-reply-to-link",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:39:56Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-in-reply-to-link",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:39:56Z",
|
||||
"content": "Link in inReplyTo",
|
||||
"inReplyTo": {
|
||||
"type": "Link",
|
||||
"href": "https://fedidev.fun/assets/note1.jsonap"
|
||||
}
|
||||
}
|
||||
}
|
||||
28
test/fixtures/fedidev.fun/in_reply_to_list.json
vendored
Normal file
28
test/fixtures/fedidev.fun/in_reply_to_list.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/in-reply-to-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:08Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-in-reply-to-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:40:08Z",
|
||||
"content": "two elements in inReplyTo",
|
||||
"inReplyTo": [
|
||||
"https://fedidev.fun/assets/note1.jsonap",
|
||||
"https://fedidev.fun/assets/note2.jsonap"
|
||||
]
|
||||
}
|
||||
}
|
||||
25
test/fixtures/fedidev.fun/missing_attributed_to.json
vendored
Normal file
25
test/fixtures/fedidev.fun/missing_attributed_to.json
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/missing-attributedto",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:42:00Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-missing-attributedto",
|
||||
"attributedTo": null,
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:42:00Z",
|
||||
"content": "object without attributedTo"
|
||||
}
|
||||
}
|
||||
|
||||
28
test/fixtures/fedidev.fun/misskey_quote_list.json
vendored
Normal file
28
test/fixtures/fedidev.fun/misskey_quote_list.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/misskey-quote-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:53Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-misskey-quote-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:53Z",
|
||||
"content": "_misskey_quote attribute as list",
|
||||
"_misskey_quote": [
|
||||
"https://fedidev.fun/assets/note1.jsonap",
|
||||
"https://fedidev.fun/assets/note2.jsonap"
|
||||
]
|
||||
}
|
||||
}
|
||||
28
test/fixtures/fedidev.fun/object_type_list.json
vendored
Normal file
28
test/fixtures/fedidev.fun/object_type_list.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/object-type-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:32Z",
|
||||
"object": {
|
||||
"type": [
|
||||
"Note"
|
||||
],
|
||||
"id": "https://fedidev.fun/objects/note-object-type-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:32Z",
|
||||
"name": "name",
|
||||
"summary": "summary",
|
||||
"content": "content"
|
||||
}
|
||||
}
|
||||
28
test/fixtures/fedidev.fun/quote_uri_list.json
vendored
Normal file
28
test/fixtures/fedidev.fun/quote_uri_list.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/quote-uri-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:52Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-quote-uri-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:52Z",
|
||||
"content": "quoteUri attribute as list",
|
||||
"quoteUri": [
|
||||
"https://fedidev.fun/assets/note1.jsonap",
|
||||
"https://fedidev.fun/assets/note2.jsonap"
|
||||
]
|
||||
}
|
||||
}
|
||||
28
test/fixtures/fedidev.fun/quote_url_list.json
vendored
Normal file
28
test/fixtures/fedidev.fun/quote_url_list.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/quote-url-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:52Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-quote-url-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:43:52Z",
|
||||
"content": "quoteUrl attribute as list",
|
||||
"quoteUrl": [
|
||||
"https://fedidev.fun/assets/note1.jsonap",
|
||||
"https://fedidev.fun/assets/note2.jsonap"
|
||||
]
|
||||
}
|
||||
}
|
||||
30
test/fixtures/fedidev.fun/tag_hashtag_missing_type.json
vendored
Normal file
30
test/fixtures/fedidev.fun/tag_hashtag_missing_type.json
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/tag-hashtag-missing-type",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:41:00Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-tag-hashtag-missing-type",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:41:00Z",
|
||||
"content": "hashtag without type",
|
||||
"tag": [
|
||||
{
|
||||
"name": "#Test"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
31
test/fixtures/fedidev.fun/tag_mention_missing_type.json
vendored
Normal file
31
test/fixtures/fedidev.fun/tag_mention_missing_type.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/tag-mention-missing-type",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:41:01Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-tag-mention-missing-type",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:41:01Z",
|
||||
"content": "mention without type",
|
||||
"tag": [
|
||||
{
|
||||
"name": "@bob",
|
||||
"href": "https://remote.example/users/bob"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
27
test/fixtures/fedidev.fun/url_list.json
vendored
Normal file
27
test/fixtures/fedidev.fun/url_list.json
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams"
|
||||
],
|
||||
"type": "Create",
|
||||
"id": "https://fedidev.fun/activity/url-list",
|
||||
"actor": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:39:06Z",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://fedidev.fun/objects/note-url-list",
|
||||
"attributedTo": "https://fedidev.fun/users/alice",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [],
|
||||
"published": "2025-11-21T14:39:06Z",
|
||||
"content": "text",
|
||||
"url": [
|
||||
"https://fedidev.fun/objects/123"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,11 @@ defmodule Pleroma.Object.ContainmentTest do
|
|||
})
|
||||
end
|
||||
|
||||
test "rejects an empty actor list without crashing" do
|
||||
assert :error ==
|
||||
Containment.contain_origin("https://example.com/objects/1", %{"actor" => []})
|
||||
end
|
||||
|
||||
test "contain_origin_from_id() catches obvious spoofing attempts" do
|
||||
data = %{
|
||||
"id" => "http://example.com/~alyssa/activities/1234.json"
|
||||
|
|
|
|||
|
|
@ -729,6 +729,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
assert Activity.get_by_ap_id(data["id"])
|
||||
end
|
||||
|
||||
test "rejects duplicate Signature headers before processing signed inbox requests", %{
|
||||
conn: conn
|
||||
} do
|
||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign_valid_signature_for_actor(data["actor"])
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> Map.update!(:req_headers, &[{"signature", "sig1=:fake-signature:"} | &1])
|
||||
|> post("/inbox", data)
|
||||
|
||||
assert "error, unsupported HTTP Message Signature" == json_response(conn, 401)
|
||||
assert [] == all_enqueued(worker: ReceiverWorker)
|
||||
end
|
||||
|
||||
test "it inserts an incoming activity into the database" <>
|
||||
"even if we can't fetch the user but have it in our db",
|
||||
%{conn: conn} do
|
||||
|
|
@ -757,6 +773,120 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
assert Activity.get_by_ap_id(data["id"])
|
||||
end
|
||||
|
||||
test "rejects unsupported HTTP Message Signatures so clients can fall back", %{conn: conn} do
|
||||
data = %{
|
||||
"type" => "Create",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"id" => "https://activitypubbot.example/activities/rfc9421-create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => [],
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"id" => "https://activitypubbot.example/objects/rfc9421-note",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"attributedTo" => "https://activitypubbot.example/user/ok",
|
||||
"content" => "hello from activitypub-bot",
|
||||
"published" => "2026-05-29T13:33:31Z",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => []
|
||||
}
|
||||
}
|
||||
|
||||
Mox.expect(Pleroma.StubbedHTTPSignaturesMock, :validate_conn, fn _conn -> false end)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> put_req_header("date", "Fri, 29 May 2026 13:33:31 GMT")
|
||||
|> put_req_header("content-digest", "sha-256=:fake-digest:")
|
||||
|> put_req_header(
|
||||
"signature-input",
|
||||
"sig1=(\"@method\" \"@target-uri\" \"date\" \"content-type\" \"content-digest\");keyid=\"https://activitypubbot.example/user/ok/publickey\";alg=\"rsa-v1_5-sha256\";created=1780061611"
|
||||
)
|
||||
|> put_req_header("signature", "sig1=:fake-signature:")
|
||||
|> post("/inbox", data)
|
||||
|
||||
assert "error, unsupported HTTP Message Signature" == json_response(conn, 401)
|
||||
assert [] == all_enqueued(worker: SignatureRetryWorker)
|
||||
end
|
||||
|
||||
test "rejects duplicate Signature headers so clients can fall back", %{conn: conn} do
|
||||
data = %{
|
||||
"type" => "Create",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"id" => "https://activitypubbot.example/activities/duplicate-signature-create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => [],
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"id" => "https://activitypubbot.example/objects/duplicate-signature-note",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"attributedTo" => "https://activitypubbot.example/user/ok",
|
||||
"content" => "hello from activitypub-bot",
|
||||
"published" => "2026-05-29T13:33:31Z",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => []
|
||||
}
|
||||
}
|
||||
|
||||
legacy_signature =
|
||||
"keyId=\"https://activitypubbot.example/user/ok#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\""
|
||||
|
||||
Mox.expect(Pleroma.StubbedHTTPSignaturesMock, :validate_conn, fn _conn -> false end)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> put_req_header("date", "Fri, 29 May 2026 13:33:31 GMT")
|
||||
|> put_req_header("digest", "SHA-256=fake-digest")
|
||||
|> put_req_header("signature", "sig1=:fake-signature:")
|
||||
|> Map.update!(:req_headers, &[{"signature", legacy_signature} | &1])
|
||||
|> post("/inbox", data)
|
||||
|
||||
assert "error, unsupported HTTP Message Signature" == json_response(conn, 401)
|
||||
assert [] == all_enqueued(worker: SignatureRetryWorker)
|
||||
end
|
||||
|
||||
test "keeps failed-signature retry for legacy signatures with Signature-Input", %{conn: conn} do
|
||||
data = %{
|
||||
"type" => "Create",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"id" => "https://activitypubbot.example/activities/legacy-create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => [],
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"id" => "https://activitypubbot.example/objects/legacy-note",
|
||||
"actor" => "https://activitypubbot.example/user/ok",
|
||||
"attributedTo" => "https://activitypubbot.example/user/ok",
|
||||
"content" => "hello from activitypub-bot",
|
||||
"published" => "2026-05-29T13:33:31Z",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => []
|
||||
}
|
||||
}
|
||||
|
||||
Mox.expect(Pleroma.StubbedHTTPSignaturesMock, :validate_conn, fn _conn -> false end)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> put_req_header("date", "Fri, 29 May 2026 13:33:31 GMT")
|
||||
|> put_req_header("digest", "SHA-256=fake-digest")
|
||||
|> put_req_header(
|
||||
"signature-input",
|
||||
"sig1=(\"@method\" \"@target-uri\" \"date\" \"content-type\" \"digest\");keyid=\"https://activitypubbot.example/user/ok/publickey\";alg=\"rsa-v1_5-sha256\";created=1780061611"
|
||||
)
|
||||
|> put_req_header(
|
||||
"signature",
|
||||
"keyId=\"https://activitypubbot.example/user/ok#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\""
|
||||
)
|
||||
|> post("/inbox", data)
|
||||
|
||||
assert "ok" == json_response(conn, 200)
|
||||
assert [_] = all_enqueued(worker: SignatureRetryWorker)
|
||||
end
|
||||
|
||||
test "does not create a forged post after failed signature retry", %{conn: conn} do
|
||||
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||
bob = insert(:user, local: false, ap_id: "https://two.com/users/bob")
|
||||
|
|
@ -1320,6 +1450,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||
assert Activity.get_by_ap_id(data["id"])
|
||||
end
|
||||
|
||||
test "rejects duplicate Signature headers", %{conn: conn, data: data} do
|
||||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign_valid_signature_for_actor(data["actor"])
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> Map.update!(:req_headers, &[{"signature", "sig1=:fake-signature:"} | &1])
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
assert "error, unsupported HTTP Message Signature" == json_response(conn, 401)
|
||||
assert [] == all_enqueued(worker: ReceiverWorker)
|
||||
end
|
||||
|
||||
test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunAttachmentsTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_data!(data) do
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
rel_path
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|> ingest_data!()
|
||||
end
|
||||
|
||||
test "drops non-http(s) attachment href" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/attachment_payto_link.json")
|
||||
assert object.data["attachment"] == []
|
||||
end
|
||||
|
||||
test "drops embedded non-attachment objects" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/attachment_embedded_note.json")
|
||||
|
||||
assert object.data["attachment"] == []
|
||||
end
|
||||
|
||||
test "accepts attachment url as list and keeps the first link" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/attachment_url_list.json")
|
||||
|
||||
[attachment] = object.data["attachment"]
|
||||
[%{"href" => href} | _] = attachment["url"]
|
||||
|
||||
assert href == "https://fedidev.fun/images/007.png"
|
||||
end
|
||||
|
||||
test "drops malformed attachment list entries" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/attachment_url_list.json") |> Jason.decode!()
|
||||
data = update_in(data, ["object", "attachment"], &["malformed" | List.wrap(&1)])
|
||||
|
||||
{_activity, object} = ingest_data!(data)
|
||||
|
||||
assert length(object.data["attachment"]) == 1
|
||||
end
|
||||
|
||||
test "accepts a URI string in an attachment url list" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/attachment_url_list.json") |> Jason.decode!()
|
||||
|
||||
data =
|
||||
put_in(data, ["object", "attachment", "url"], [
|
||||
"https://fedidev.fun/images/007.png"
|
||||
])
|
||||
|
||||
{_activity, object} = ingest_data!(data)
|
||||
|
||||
assert [%{"url" => [%{"href" => "https://fedidev.fun/images/007.png"}]}] =
|
||||
object.data["attachment"]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunEmojiTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_data!(data) do
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
rel_path
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|> ingest_data!()
|
||||
end
|
||||
|
||||
test "ingests Emoji tag with string icon" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/emoji_icon_string.json")
|
||||
assert object.data["emoji"]["cow"] == "https://fedidev.fun/static/cow.png"
|
||||
end
|
||||
|
||||
test "ingests Emoji tag with icon missing type" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/emoji_icon_url_missing_type.json")
|
||||
|
||||
assert object.data["emoji"]["cow2"] == "https://fedidev.fun/static/cow.png"
|
||||
end
|
||||
|
||||
test "ignores Emoji tag missing icon" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/emoji_missing_icon.json")
|
||||
assert object.data["emoji"] == %{}
|
||||
end
|
||||
|
||||
test "ignores Emoji tag missing a string name" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/emoji_icon_string.json") |> Jason.decode!()
|
||||
data = put_in(data, ["object", "tag", Access.at(0), "name"], nil)
|
||||
|
||||
{_activity, object} = ingest_data!(data)
|
||||
|
||||
assert object.data["emoji"] == %{}
|
||||
end
|
||||
|
||||
test "ignores Emoji tag with a non-http icon" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/emoji_icon_string.json") |> Jason.decode!()
|
||||
data = put_in(data, ["object", "tag", Access.at(0), "icon"], "file:///tmp/cow.png")
|
||||
|
||||
{_activity, object} = ingest_data!(data)
|
||||
|
||||
assert object.data["emoji"] == %{}
|
||||
end
|
||||
|
||||
test "normalizes a list-typed Emoji tag before building the emoji map" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/emoji_icon_string.json") |> Jason.decode!()
|
||||
|
||||
data =
|
||||
put_in(data, ["object", "tag", Access.at(0), "type"], [
|
||||
"https://example.com/ns#CustomTag",
|
||||
"Emoji"
|
||||
])
|
||||
|
||||
{_activity, object} = ingest_data!(data)
|
||||
|
||||
assert object.data["emoji"]["cow"] == "https://fedidev.fun/static/cow.png"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunInReplyToTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
data = rel_path |> File.read!() |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
test "normalizes Link inReplyTo to a string" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/in_reply_to_link.json")
|
||||
assert object.data["inReplyTo"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
|
||||
test "normalizes list inReplyTo to the first object ID" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/in_reply_to_list.json")
|
||||
assert object.data["inReplyTo"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
|
||||
test "drops invalid map shapes in inReplyTo" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/in_reply_to_collection.json")
|
||||
|
||||
assert object.data["inReplyTo"] == nil
|
||||
end
|
||||
|
||||
test "accepts embedded objects in inReplyTo" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/in_reply_to_embedded_note.json")
|
||||
|
||||
assert object.data["inReplyTo"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunMissingAttributedToTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
test "inherits attributedTo from surrounding activity" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/missing_attributed_to.json") |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
assert object.data["attributedTo"] == data["actor"]
|
||||
assert object.data["actor"] == data["actor"]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunObjectTypeListTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
data = rel_path |> File.read!() |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
test "accepts object type as a list and stores the first type" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/object_type_list.json")
|
||||
assert object.data["type"] == "Note"
|
||||
end
|
||||
|
||||
test "selects a supported type after an extension type" do
|
||||
data = File.read!("test/fixtures/fedidev.fun/object_type_list.json") |> Jason.decode!()
|
||||
data = put_in(data, ["object", "type"], ["https://example.com/ns#CustomType", "Note"])
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
assert object.data["type"] == "Note"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunQuoteUrlListTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
data = rel_path |> File.read!() |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
test "normalizes quoteUri list to the first object ID" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/quote_uri_list.json")
|
||||
assert object.data["quoteUrl"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
|
||||
test "normalizes quoteUrl list to the first object ID" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/quote_url_list.json")
|
||||
assert object.data["quoteUrl"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
|
||||
test "normalizes _misskey_quote list to the first object ID" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/misskey_quote_list.json")
|
||||
assert object.data["quoteUrl"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunTagInferenceTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
data = rel_path |> File.read!() |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
test "infers Hashtag type when missing" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/tag_hashtag_missing_type.json")
|
||||
|
||||
assert "test" in Object.hashtags(object)
|
||||
end
|
||||
|
||||
test "infers Mention type when missing" do
|
||||
{_activity, object} =
|
||||
ingest_fixture!("test/fixtures/fedidev.fun/tag_mention_missing_type.json")
|
||||
|
||||
assert Enum.any?(object.data["tag"], fn
|
||||
%{"type" => "Mention", "href" => "https://remote.example/users/bob"} -> true
|
||||
_ -> false
|
||||
end)
|
||||
end
|
||||
|
||||
test "normalizes a list-typed tag type" do
|
||||
data =
|
||||
File.read!("test/fixtures/fedidev.fun/tag_hashtag_missing_type.json") |> Jason.decode!()
|
||||
|
||||
data = put_in(data, ["object", "tag", Access.at(0), "type"], ["Hashtag"])
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
assert "test" in Object.hashtags(object)
|
||||
end
|
||||
|
||||
test "ignores a list-typed Hashtag without a string name" do
|
||||
data =
|
||||
File.read!("test/fixtures/fedidev.fun/tag_hashtag_missing_type.json") |> Jason.decode!()
|
||||
|
||||
data = put_in(data, ["object", "tag", Access.at(0), "type"], ["Hashtag"])
|
||||
data = put_in(data, ["object", "tag", Access.at(0), "name"], nil)
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
assert Object.hashtags(object) == []
|
||||
end
|
||||
|
||||
test "infers a Link before deriving quoteUrl" do
|
||||
data =
|
||||
File.read!("test/fixtures/fedidev.fun/tag_hashtag_missing_type.json") |> Jason.decode!()
|
||||
|
||||
data =
|
||||
put_in(data, ["object", "tag"], [
|
||||
%{
|
||||
"href" => "https://fedidev.fun/assets/note1.jsonap",
|
||||
"mediaType" => "application/activity+json"
|
||||
}
|
||||
])
|
||||
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
assert object.data["quoteUrl"] == "https://fedidev.fun/assets/note1.jsonap"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunUrlListTest do
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
use Pleroma.DataCase
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
|
||||
case User.get_cached_by_ap_id(ap_id) do
|
||||
%User{} ->
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
insert(:user,
|
||||
local: false,
|
||||
ap_id: ap_id,
|
||||
follower_address: ap_id <> "/followers",
|
||||
following_address: ap_id <> "/following",
|
||||
featured_address: ap_id <> "/collections/featured",
|
||||
inbox: ap_id <> "/inbox"
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp ingest_fixture!(rel_path) do
|
||||
data = rel_path |> File.read!() |> Jason.decode!()
|
||||
ensure_remote_actor!(data["actor"])
|
||||
|
||||
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
|
||||
object = Object.normalize(activity.data["object"], fetch: false)
|
||||
|
||||
{activity, object}
|
||||
end
|
||||
|
||||
test "normalizes object url list to a string" do
|
||||
{_activity, object} = ingest_fixture!("test/fixtures/fedidev.fun/url_list.json")
|
||||
assert object.data["url"] == "https://fedidev.fun/objects/123"
|
||||
end
|
||||
end
|
||||
|
|
@ -572,11 +572,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
|
|||
Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
|
||||
|
||||
modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
|
||||
assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
|
||||
assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
|
||||
|
||||
object_with_reply = Map.put(data["object"], "inReplyTo", [])
|
||||
modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
|
||||
assert modified_object["inReplyTo"] == []
|
||||
assert modified_object["inReplyTo"] == nil
|
||||
end
|
||||
|
||||
test "returns modified object when allowed incoming reply", %{data: data} do
|
||||
|
|
@ -671,13 +671,21 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
|
|||
test "returns object with emoji when object contains list tags" do
|
||||
assert Transmogrifier.fix_emoji(%{
|
||||
"tag" => [
|
||||
%{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
|
||||
%{
|
||||
"type" => "Emoji",
|
||||
"name" => ":bib:",
|
||||
"icon" => %{"url" => "https://example.com/test"}
|
||||
},
|
||||
%{"type" => "Hashtag"}
|
||||
]
|
||||
}) == %{
|
||||
"emoji" => %{"bib" => "/test"},
|
||||
"emoji" => %{"bib" => "https://example.com/test"},
|
||||
"tag" => [
|
||||
%{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
|
||||
%{
|
||||
"icon" => %{"url" => "https://example.com/test"},
|
||||
"name" => ":bib:",
|
||||
"type" => "Emoji"
|
||||
},
|
||||
%{"type" => "Hashtag"}
|
||||
]
|
||||
}
|
||||
|
|
@ -685,10 +693,28 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
|
|||
|
||||
test "returns object with emoji when object contains map tag" do
|
||||
assert Transmogrifier.fix_emoji(%{
|
||||
"tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
|
||||
"tag" => %{
|
||||
"type" => "Emoji",
|
||||
"name" => ":bib:",
|
||||
"icon" => %{"url" => "https://example.com/test"}
|
||||
}
|
||||
}) == %{
|
||||
"emoji" => %{"bib" => "/test"},
|
||||
"tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
|
||||
"emoji" => %{"bib" => "https://example.com/test"},
|
||||
"tag" => %{
|
||||
"icon" => %{"url" => "https://example.com/test"},
|
||||
"name" => ":bib:",
|
||||
"type" => "Emoji"
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "fix_tag/1" do
|
||||
test "ignores malformed Hashtag names and tag entries" do
|
||||
tag = %{"type" => "Hashtag", "name" => 123}
|
||||
|
||||
assert Transmogrifier.fix_tag(%{"tag" => [tag, "malformed"]}) == %{
|
||||
"tag" => [tag, "malformed"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -50,6 +50,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
|
|||
assert user.bio == "<p>Some bio</p>"
|
||||
end
|
||||
|
||||
test "it selects an actor type after an extension type" do
|
||||
user = insert(:user, local: false)
|
||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
|
||||
|
||||
object =
|
||||
update_data["object"]
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|> Map.put("id", user.ap_id)
|
||||
|> Map.put("type", ["https://example.com/ns#CustomActor", "Person"])
|
||||
|
||||
update_data =
|
||||
update_data
|
||||
|> Map.put("actor", user.ap_id)
|
||||
|> Map.put("object", object)
|
||||
|
||||
assert {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data)
|
||||
assert User.get_cached_by_ap_id(user.ap_id).name == "gargle"
|
||||
end
|
||||
|
||||
test "it works with alsoKnownAs" do
|
||||
%{ap_id: actor} = insert(:user, local: false)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue