commit 28bb8e94426eb0795ff2dca568b554251613c09d Author: mStar Date: Mon Jul 29 10:01:49 2024 +0200 Exported my ap implementation to separate lib Not done yet diff --git a/baseInterface.go b/baseInterface.go new file mode 100644 index 0000000..025fd5e --- /dev/null +++ b/baseInterface.go @@ -0,0 +1,30 @@ +package goap + +// Interface for every struct that can be part of an ActivityPub object +type BaseApChain interface { + // Get the next "object" in the chain (or self if last element in chain) + // Though preferably the last element should always be a BaseObject + // The 2nd parameter indicates whether the returned value is different from the one the function is called on + // So true => Is a different object, false => is self + GetSelfOrBase() (BaseApChain, bool) + // Convert the chain to a map + // Should include the rest of the chain (extend the map the underlying object returns) + MarshalToMap() map[string]any +} + +// The minimum data every AP object has +type BaseObject struct { + Id string + Type string +} + +func (b *BaseObject) GetSelfOrBase() (BaseApChain, bool) { + return b, false +} + +func (b *BaseObject) MarshalToMap() map[string]any { + return map[string]any{ + KEY_ID: b.Id, + KEY_TYPE: b.Type, + } +} diff --git a/constants.go b/constants.go new file mode 100644 index 0000000..0e8dca0 --- /dev/null +++ b/constants.go @@ -0,0 +1,111 @@ +package goap + +const ( + KEY_ID = "@id" // Value of type string + KEY_TYPE = "@type" // Value of type string slice / activitystreams object url slice + KEY_VALUE = "@value" // Could be any type really +) + +const ( + KEY_MASTO_DEVICES = "http://joinmastodon.org/ns#devices" // No idea what this is, but Masto includes it + KEY_MASTO_DISCOVERABLE = "http://joinmastodon.org/ns#discoverable" // iirc this is whether the object can be found by crawlers + KEY_MASTO_FEATURED = "http://joinmastodon.org/ns#featured" // Users tagged? I think + KEY_MASTO_FEATURED_TAGS = "http://joinmastodon.org/ns#featuredTags" // Hashtags included, I think + KEY_MASTO_INDEXABLE = "http://joinmastodon.org/ns#indexable" // Is the object crawlable round 2 + KEY_MASTO_MEMORIAL = "http://joinmastodon.org/ns#memorial" // Account dead and disabled? + KEY_MASTO_EMOJI = "http://joinmastodon.org/ns#Emoji" // Object is an emoji +) + +const ( + KEY_W3_INBOX = "http://www.w3.org/ns/ldp#inbox" // Where to send activities to + KEY_W3_SECURITY_PUBLICKEY = "https://w3id.org/security#publicKey" // Public key of the account + KEY_W3_SECURITY_OWNER = "https://w3id.org/security#owner" // Owner of the public key + KEY_W3_SECURITY_PUBLICKEYPEM = "https://w3id.org/security#publicKeyPem" // Pem content of the key + KEY_W3_SECURITY_KEY = "https://w3id.org/security#Key" // Object is a PublicKey + KEY_W3_VCARD_ADRESS = "http://www.w3.org/2006/vcard/ns#Address" // Vcard address of an account + KEY_W3_VCARD_BIRTHDAY = "http://www.w3.org/2006/vcard/ns#bday" // Vcard birthday of an account +) + +const ( + KEY_ACTIVITYSTREAMS_ALSOKNOWNAS = "https://www.w3.org/ns/activitystreams#alsoKnownAs" // Lists of usernames? + KEY_ACTIVITYSTREAMS_ATTACHMENTS = "https://www.w3.org/ns/activitystreams#attachment" // Attached elements like emotes and hashtags + KEY_ACTIVITYSTREAMS_NAME = "https://www.w3.org/ns/activitystreams#name" // Name of the object + KEY_ACTIVITYSTREAMS_ENDPOINTS = "https://www.w3.org/ns/activitystreams#endpoints" // list of assocciated endpoints + KEY_ACTIVITYSTREAMS_SHAREDINBOX = "https://www.w3.org/ns/activitystreams#sharedInbox" // Link to the shared inbox of the server + KEY_ACTIVITYSTREAMS_FOLLOWERS = "https://www.w3.org/ns/activitystreams#followers" // Who is following the account + KEY_ACTIVITYSTREAMS_FOLLOWING = "https://www.w3.org/ns/activitystreams#following" // Who is this account following + KEY_ACTIVITYSTREAMS_ICON = "https://www.w3.org/ns/activitystreams#icon" // User icon + KEY_ACTIVITYSTREAMS_MEDIATYPE = "https://www.w3.org/ns/activitystreams#mediaType" // What type of media is this? Example image/jpeg + KEY_ACTIVITYSTREAMS_URL = "https://www.w3.org/ns/activitystreams#url" // Some url + KEY_ACTIVITYSTREAMS_IMAGE = "https://www.w3.org/ns/activitystreams#image" // Account banner + KEY_ACTIVITYSTREAMS_RESTRICTED_FOLLOW = "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers" // Does the account manually approve follow requests + KEY_ACTIVITYSTREAMS_OUTBOX = "https://www.w3.org/ns/activitystreams#outbox" // Link to the account's outbox + KEY_ACTIVITYSTREAMS_PREFFEREDUSERNAME = "https://www.w3.org/ns/activitystreams#preferredUsername" // What the shown username is + KEY_ACTIVITYSTREAMS_PUBLISHED = "https://www.w3.org/ns/activitystreams#published" // When an object was created + KEY_ACTIVITYSTREAMS_SUMMARY = "https://www.w3.org/ns/activitystreams#summary" // Summary of an account or the cw of a note + KEY_ACTIVITYSTREAMS_TAG = "https://www.w3.org/ns/activitystreams#tag" // A tag, usually hashtags included somewhere + KEY_ACTIVITYSTREAMS_CC = "https://www.w3.org/ns/activitystreams#cc" // Urls also included in the object + KEY_ACTIVITYSTREAMS_TO = "https://www.w3.org/ns/activitystreams#to" // Urls to send an activity to + KEY_ACTIVITYSTREAMS_OBJECT = "https://www.w3.org/ns/activitystreams#object" // Object url and sometimes value + KEY_ACTIVITYSTREAMS_HREF = "https://www.w3.org/ns/activitystreams#href" // Some url with id + KEY_ACTIVITYSTREAMS_ATTRIBUTEDTO = "https://www.w3.org/ns/activitystreams#attributedTo" // Creator of object? + KEY_ACTIVITYSTREAMS_CONTENT = "https://www.w3.org/ns/activitystreams#content" // (String) content of an object + KEY_ACTIVITYSTREAMS_REPLIES = "https://www.w3.org/ns/activitystreams#replies" // Object containing the replies. Should always be a Collection + KEY_ACTIVITYSTREAMS_SENSITIVE = "https://www.w3.org/ns/activitystreams#sensitive" // Whether the content of the object is marked as sensitive + KEY_ACTIVITYSTREAMS_PUBLIC = "https://www.w3.org/ns/activitystreams#Public" // Note target + KEY_ACTIVITYSTREAMS_UPDATED = "https://www.w3.org/ns/activitystreams#updated" // When the content was last updated + + // Object types (I think) + // Those are values the object type can have + + KEY_ACTIVITYSTREAMS_ACTOR = "https://www.w3.org/ns/activitystreams#actor" + KEY_ACTIVITYSTREAMS_FOLLOW = "https://www.w3.org/ns/activitystreams#Follow" // Object is an activity of type follow + KEY_ACTIVITYSTREAMS_PERSON = "https://www.w3.org/ns/activitystreams#Person" // Object is of type Person + KEY_ACTIVITYSTREAMS_CREATE = "https://www.w3.org/ns/activitystreams#Create" // Object is an activity of type Create + KEY_ACTIVITYSTREAMS_COLLECTION = "https://www.w3.org/ns/activitystreams#Collection" // Object is a collection of things + KEY_ACTIVITYSTREAMS_COLLECTIONPAGE = "https://www.w3.org/ns/activitystreams#CollectionPage" // Object is a page of a collection + KEY_ACTIVITYSTREAMS_HASHTAG = "https://www.w3.org/ns/activitystreams#Hashtag" // Object is a hashtag + KEY_ACTIVITYSTREAMS_LIKE = "https://www.w3.org/ns/activitystreams#Like" // Object is an activity of type like + KEY_ACTIVITYSTREAMS_NOTE = "https://www.w3.org/ns/activitystreams#Note" // Object is of type Note + + KEY_ACTIVITYSTREAMS_FIRST = "https://www.w3.org/ns/activitystreams#first" // First page in a collection + KEY_ACTIVITYSTREAMS_ITEMS = "https://www.w3.org/ns/activitystreams#items" // Items in this collection page + KEY_ACTIVITYSTREAMS_NEXT = "https://www.w3.org/ns/activitystreams#next" // Next page in a collection + KEY_ACTIVITYSTREAMS_PARTOF = "https://www.w3.org/ns/activitystreams#partOf" // Collection the current page is a part of + + KEY_ACTIVITYSTREAMS_OAUTHAUTHORIZATION = "https://www.w3.org/ns/activitystreams#oauthAuthorizationEndpoint" // Endpoint url for oauth login? + KEY_ACTIVITYSTREAMS_OAUTHTOKEN = "https://www.w3.org/ns/activitystreams#oauthTokenEndpoint" // Endpoint url for oauth token verification? + KEY_ACTIVITYSTREAMS_UPLOADMEDIA = "https://www.w3.org/ns/activitystreams#uploadMedia" // Endpoint url to upload media to? +) + +const ( + KEY_SCHEMA_VALUE = "http://schema.org#value" // The value for some field + KEY_SCHEMA_PROPERTYVALUE = "http://schema.org#PropertyValue" +) + +const ( + KEY_MISSKEY_MKSUMMARY = "https://misskey-hub.net/ns#_misskey_summary" // Misskey specific formatted summary + KEY_MISSKEY_ISCAT = "https://misskey-hub.net/ns#isCat" // Does the account identify as cat? + KEY_FIREFISH_SPEAKASCAT = "https://joinfirefish.org/ns#speakAsCat" // Does the account speak like a cat? +) + +const ( + KEY_LITEPUB_CAPABILITIES = "http://litepub.social/ns#capabilities" + KEY_LITEPUB_OAUTHREGISTRATION = "http://litepub.social/ns#oauthRegistrationEndpoint" +) + +const ( + KEY_XMLSCHEMA_DATETIME = "http://www.w3.org/2001/XMLSchema#dateTime" // Type value for published value field +) + +// NOTE: ostatus.org seems to be redirecting to some weird scam(?) page +const ( + KEY_OSTATUS_ATOMURI = "http://ostatus.org#atomUri" + KEY_OSTATUS_CONVERSATION = "http://ostatus.org#conversation" +) + +const ( + KEY_MYSTERIOUS_NOINDEX = "_:noindex" + KEY_MYSTERIOUS_BACKGROUNDURL = "_:backgroundUrl" + KEY_MYSTERIOUS_FEATURED = "_:featured" +) diff --git a/examples/akkoma_account.json b/examples/akkoma_account.json new file mode 100644 index 0000000..73c7248 --- /dev/null +++ b/examples/akkoma_account.json @@ -0,0 +1,429 @@ +[ + { + "@id": "https://labyrinth.zone/users/yassie_j", + "@type": [ + "https://www.w3.org/ns/activitystreams#Person" + ], + "_:backgroundUrl": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/media/234dff2e-a170-488f-ac44-219715c0ec78/march21_.png" + } + ] + } + ], + "_:featured": [ + { + "@language": "und", + "@value": "https://labyrinth.zone/users/yassie_j/collections/featured" + } + ], + "http://joinmastodon.org/ns#discoverable": [ + { + "@value": false + } + ], + "http://litepub.social/ns#capabilities": [ + {} + ], + "http://www.w3.org/ns/ldp#inbox": [ + { + "@id": "https://labyrinth.zone/users/yassie_j/inbox" + } + ], + "https://w3id.org/security#publicKey": [ + { + "@id": "https://labyrinth.zone/users/yassie_j#main-key", + "https://w3id.org/security#owner": [ + { + "@id": "https://labyrinth.zone/users/yassie_j" + } + ], + "https://w3id.org/security#publicKeyPem": [ + { + "@language": "und", + "@value": "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoqGqzjzGW3JueVTcJOa 1pg87fus3ed7gcLG3fRHQrXCoIT4D++AeGjLBwiznq2nw7RNBOekOH3qWQe1rrIC v0b+dwDFoEmEeTZLMw1htwlLzm6BIUCukIwO8fPtB7EbwpzMbg5G1URzaOXPvtQv 2YZMdYO04z9sykj+ebVujHXAv1nyB+PAkZWxgmlKlLX4Vv3f5lVlxBU3CmHQKhoD WYNWVwBuu4ER6sspgWRjpTiyDsna7vEpUIK69oOckg6MXnTVmQcN95IufttYry8f e3m/XpsorTNlaFpNpUJozbmNiy6qD8PwDpzcXHAtDrlVg05DLps0N9FIRIcwfHmg AQIDAQAB -----END PUBLIC KEY----- " + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#alsoKnownAs": [ + { + "@id": "https://0w0.is/users/yassie_j" + } + ], + "https://www.w3.org/ns/activitystreams#attachment": [ + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "28 | 13/07" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Age" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "They/Them" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Pronouns" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "Birmingham, Terf Island 🇬🇧" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Location" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "Ask!" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Discord/Matrix/Signal" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "\u003ca href=\"http://twitch.tv/yassie_j\" rel=\"ugc\"\u003etwitch.tv/yassie_j\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Play games" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "\u003ca href=\"https://yasposting.mae.lgbt/\" rel=\"ugc\"\u003ehttps://yasposting.mae.lgbt/\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Writing" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@language": "und", + "@value": "\u003ca href=\"https://podcasters.spotify.com/pod/show/yscst\" rel=\"ugc\"\u003ehttps://podcasters.spotify.com/pod/show/yscst\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "Yascast Podcast" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#endpoints": [ + { + "http://litepub.social/ns#oauthRegistrationEndpoint": [ + { + "@id": "https://labyrinth.zone/api/v1/apps" + } + ], + "https://www.w3.org/ns/activitystreams#oauthAuthorizationEndpoint": [ + { + "@id": "https://labyrinth.zone/oauth/authorize" + } + ], + "https://www.w3.org/ns/activitystreams#oauthTokenEndpoint": [ + { + "@id": "https://labyrinth.zone/oauth/token" + } + ], + "https://www.w3.org/ns/activitystreams#sharedInbox": [ + { + "@id": "https://labyrinth.zone/inbox" + } + ], + "https://www.w3.org/ns/activitystreams#uploadMedia": [ + { + "@id": "https://labyrinth.zone/api/ap/upload_media" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#followers": [ + { + "@id": "https://labyrinth.zone/users/yassie_j/followers" + } + ], + "https://www.w3.org/ns/activitystreams#following": [ + { + "@id": "https://labyrinth.zone/users/yassie_j/following" + } + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://media.labyrinth.zone/media/4aafeaf08cfd977dae9a02dae8f9519cb953b73348773c1b65882cdce78fa137.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#image": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/media/df73feb4-277b-4690-9c2f-d959331df42e/DT7Y0V7UMAAHsGb.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers": [ + { + "@value": true + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": "yassie_gay :baba_baba_yaseen: :agenderFlag: :transgenderFlag: " + } + ], + "https://www.w3.org/ns/activitystreams#outbox": [ + { + "@id": "https://labyrinth.zone/users/yassie_j/outbox" + } + ], + "https://www.w3.org/ns/activitystreams#preferredUsername": [ + { + "@language": "und", + "@value": "yassie_j" + } + ], + "https://www.w3.org/ns/activitystreams#summary": [ + { + "@language": "und", + "@value": "A shitposter, Shloer-addict, and cake-lover. I love hot chocolate, hugs, and cuteness.\u003cbr/\u003e\u003cbr/\u003e[Follow reqs are never going to be accepted unless I know you]\u003cbr/\u003e\u003cbr/\u003eProfile picture created by \u003cspan class=\"h-card\"\u003e\u003ca class=\"u-url mention\" data-user=\"AbTbJgnbBbGbuLkiHI\" href=\"https://nyan.network/users/len\" rel=\"ugc\"\u003e@\u003cspan\u003elen@nyan.network\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e!!! \u003cbr/\u003e\u003cbr/\u003eAgender :neofox_flag_agender: :neocat_flag_trans: \u003cbr/\u003e🇧🇩 heritage in 🇬🇧.\u003cbr/\u003e\u003cbr/\u003e\u003cbr/\u003eMy #1 girl is Nepnep.\u003cbr/\u003e\u003cbr/\u003eI used to be \u003cspan class=\"h-card\"\u003e\u003ca class=\"u-url mention\" data-user=\"AgQWwAvHNRuGTQiAHQ\" href=\"https://snowdin.town/users/yassie_j\" rel=\"ugc\"\u003e@\u003cspan\u003eyassie_j@snowdin.town\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e and \u003cspan class=\"h-card\"\u003e\u003ca class=\"u-url mention\" data-user=\"AbSOsWTdgPeYm5L4Ns\" href=\"https://0w0.is/users/yassie_j\" rel=\"ugc\"\u003e@\u003cspan\u003eyassie_j@0w0.is\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e and always will be. \u003cbr/\u003e\u003cbr/\u003e\u003ca href=\"http://Mastodon.lol\"\u003eMastodon.lol\u003c/a\u003e (rest in piss), joined 16 Nov 2022 --\u0026gt; \u003ca href=\"http://snowdin.town\"\u003esnowdin.town\u003c/a\u003e (rest in peace), joined 7 Feb 2023 --\u0026gt; \u003ca href=\"http://0w0.is\"\u003e0w0.is\u003c/a\u003e (rest in peace), joined 4 Aug 2023 --\u0026gt; joined here 12 Jan 2024\u003cbr/\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@id": "https://labyrinth.zone/emoji/flags/agenderFlag.webp", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/emoji/flags/agenderFlag.webp" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": ":agenderFlag:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "1970-01-01T00:00:00Z" + } + ] + }, + { + "@id": "https://labyrinth.zone/emoji/baba/c19f6a06-54ca-41e7-a461-6b44deb913c7", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/emoji/baba/c19f6a06-54ca-41e7-a461-6b44deb913c7" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": ":baba_baba_yaseen:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "1970-01-01T00:00:00Z" + } + ] + }, + { + "@id": "https://labyrinth.zone/emoji/neocat/neocat_flag_trans_256.png", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/emoji/neocat/neocat_flag_trans_256.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": ":neocat_flag_trans:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "1970-01-01T00:00:00Z" + } + ] + }, + { + "@id": "https://labyrinth.zone/emoji/neofox/neofox_flag_agender_256.png", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/emoji/neofox/neofox_flag_agender_256.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": ":neofox_flag_agender:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "1970-01-01T00:00:00Z" + } + ] + }, + { + "@id": "https://labyrinth.zone/emoji/flags/transgenderFlag.webp", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/emoji/flags/transgenderFlag.webp" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@language": "und", + "@value": ":transgenderFlag:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "1970-01-01T00:00:00Z" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://labyrinth.zone/users/yassie_j" + } + ] + } +] diff --git a/examples/masto_account.json b/examples/masto_account.json new file mode 100644 index 0000000..3f739b0 --- /dev/null +++ b/examples/masto_account.json @@ -0,0 +1,185 @@ +[ + { + "@id": "https://mastodon.social/users/Gargron", + "@type": [ + "https://www.w3.org/ns/activitystreams#Person" + ], + "http://joinmastodon.org/ns#devices": [ + { + "@id": "https://mastodon.social/users/Gargron/collections/devices" + } + ], + "http://joinmastodon.org/ns#discoverable": [ + { + "@value": true + } + ], + "http://joinmastodon.org/ns#featured": [ + { + "@id": "https://mastodon.social/users/Gargron/collections/featured" + } + ], + "http://joinmastodon.org/ns#featuredTags": [ + { + "@id": "https://mastodon.social/users/Gargron/collections/tags" + } + ], + "http://joinmastodon.org/ns#indexable": [ + { + "@value": true + } + ], + "http://joinmastodon.org/ns#memorial": [ + { + "@value": false + } + ], + "http://www.w3.org/ns/ldp#inbox": [ + { + "@id": "https://mastodon.social/users/Gargron/inbox" + } + ], + "https://w3id.org/security#publicKey": [ + { + "@id": "https://mastodon.social/users/Gargron#main-key", + "https://w3id.org/security#owner": [ + { + "@id": "https://mastodon.social/users/Gargron" + } + ], + "https://w3id.org/security#publicKeyPem": [ + { + "@value": "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXc4vkECU2/CeuSo1wtn Foim94Ne1jBMYxTZ9wm2YTdJq1oiZKif06I2fOqDzY/4q/S9uccrE9Bkajv1dnkO Vm31QjWlhVpSKynVxEWjVBO5Ienue8gND0xvHIuXf87o61poqjEoepvsQFElA5ym ovljWGSA/jpj7ozygUZhCXtaS2W5AD5tnBQUpcO0lhItYPYTjnmzcc4y2NbJV8hz 2s2G8qKv8fyimE23gY1XrPJg+cRF+g4PqFXujjlJ7MihD9oqtLGxbu7o1cifTn3x BfIdPythWu5b4cujNsB3m3awJjVmx+MHQ9SugkSIYXV0Ina77cTNS0M2PYiH1PFR TwIDAQAB -----END PUBLIC KEY----- " + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#alsoKnownAs": [ + { + "@id": "https://tooting.ai/users/Gargron" + } + ], + "https://www.w3.org/ns/activitystreams#attachment": [ + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "\u003ca href=\"https://www.patreon.com/mastodon\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"\"\u003epatreon.com/mastodon\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Patreon" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "\u003ca href=\"https://github.com/Gargron\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003egithub.com/Gargron\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "GitHub" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#endpoints": [ + { + "https://www.w3.org/ns/activitystreams#sharedInbox": [ + { + "@id": "https://mastodon.social/inbox" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#followers": [ + { + "@id": "https://mastodon.social/users/Gargron/followers" + } + ], + "https://www.w3.org/ns/activitystreams#following": [ + { + "@id": "https://mastodon.social/users/Gargron/following" + } + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/png" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://files.mastodon.social/accounts/avatars/000/000/001/original/a0a49d80c3de5f75.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#image": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/jpeg" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://files.mastodon.social/accounts/headers/000/000/001/original/d13e4417706a5fec.jpg" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers": [ + { + "@value": false + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Eugen Rochko" + } + ], + "https://www.w3.org/ns/activitystreams#outbox": [ + { + "@id": "https://mastodon.social/users/Gargron/outbox" + } + ], + "https://www.w3.org/ns/activitystreams#preferredUsername": [ + { + "@value": "Gargron" + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2016-03-16T00:00:00Z" + } + ], + "https://www.w3.org/ns/activitystreams#summary": [ + { + "@value": "\u003cp\u003eFounder of \u003cspan class=\"h-card\" translate=\"no\"\u003e\u003ca href=\"https://mastodon.social/@Mastodon\" class=\"u-url mention\"\u003e@\u003cspan\u003eMastodon\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e. Film photography, prog metal, Dota 2. Likes all things analog.\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#tag": [], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://mastodon.social/@Gargron" + } + ] + } +] diff --git a/examples/masto_follow_request.json b/examples/masto_follow_request.json new file mode 100644 index 0000000..d483b73 --- /dev/null +++ b/examples/masto_follow_request.json @@ -0,0 +1,18 @@ +[ + { + "@id": "https://activitypub.academy/1e8a5594-eff7-4946-86fe-84d82d0a14ae", + "@type": [ + "https://www.w3.org/ns/activitystreams#Follow" + ], + "https://www.w3.org/ns/activitystreams#actor": [ + { + "@id": "https://activitypub.academy/users/dadacio_dashdorrol" + } + ], + "https://www.w3.org/ns/activitystreams#object": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ] + } +] diff --git a/examples/masto_note_cwd.json b/examples/masto_note_cwd.json new file mode 100644 index 0000000..44d5552 --- /dev/null +++ b/examples/masto_note_cwd.json @@ -0,0 +1,91 @@ +[ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681", + "@type": [ + "https://www.w3.org/ns/activitystreams#Note" + ], + "http://ostatus.org#atomUri": [ + { + "@value": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681" + } + ], + "http://ostatus.org#conversation": [ + { + "@value": "tag:activitypub.academy,2024-07-28:objectId=183655:objectType=Conversation" + } + ], + "https://www.w3.org/ns/activitystreams#attachment": [], + "https://www.w3.org/ns/activitystreams#attributedTo": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol" + } + ], + "https://www.w3.org/ns/activitystreams#cc": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/followers" + } + ], + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": "\u003cp\u003enote with cw\u003c/p\u003e" + }, + { + "@language": "en", + "@value": "\u003cp\u003enote with cw\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2024-07-28T09:57:10Z" + } + ], + "https://www.w3.org/ns/activitystreams#replies": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681/replies", + "@type": [ + "https://www.w3.org/ns/activitystreams#Collection" + ], + "https://www.w3.org/ns/activitystreams#first": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#CollectionPage" + ], + "https://www.w3.org/ns/activitystreams#items": [], + "https://www.w3.org/ns/activitystreams#next": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681/replies?only_other_accounts=true\u0026page=true" + } + ], + "https://www.w3.org/ns/activitystreams#partOf": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681/replies" + } + ] + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#sensitive": [ + { + "@value": true + } + ], + "https://www.w3.org/ns/activitystreams#summary": [ + { + "@value": "cool message" + } + ], + "https://www.w3.org/ns/activitystreams#tag": [], + "https://www.w3.org/ns/activitystreams#to": [ + { + "@id": "https://www.w3.org/ns/activitystreams#Public" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://activitypub.academy/@benules_llorvatol/112863519062185681" + } + ] + } +] diff --git a/examples/masto_note_tags.json b/examples/masto_note_tags.json new file mode 100644 index 0000000..ac3e7bf --- /dev/null +++ b/examples/masto_note_tags.json @@ -0,0 +1,102 @@ +[ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863146588107916", + "@type": [ + "https://www.w3.org/ns/activitystreams#Note" + ], + "http://ostatus.org#atomUri": [ + { + "@value": "https://activitypub.academy/users/benules_llorvatol/statuses/112863146588107916" + } + ], + "http://ostatus.org#conversation": [ + { + "@value": "tag:activitypub.academy,2024-07-28:objectId=183652:objectType=Conversation" + } + ], + "https://www.w3.org/ns/activitystreams#attachment": [], + "https://www.w3.org/ns/activitystreams#attributedTo": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol" + } + ], + "https://www.w3.org/ns/activitystreams#cc": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/followers" + } + ], + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": "\u003cp\u003emessage with a \u003ca href=\"https://activitypub.academy/tags/tag\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003etag\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e" + }, + { + "@language": "en", + "@value": "\u003cp\u003emessage with a \u003ca href=\"https://activitypub.academy/tags/tag\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003etag\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2024-07-28T08:22:26Z" + } + ], + "https://www.w3.org/ns/activitystreams#replies": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863146588107916/replies", + "@type": [ + "https://www.w3.org/ns/activitystreams#Collection" + ], + "https://www.w3.org/ns/activitystreams#first": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#CollectionPage" + ], + "https://www.w3.org/ns/activitystreams#items": [], + "https://www.w3.org/ns/activitystreams#next": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863146588107916/replies?only_other_accounts=true\u0026page=true" + } + ], + "https://www.w3.org/ns/activitystreams#partOf": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863146588107916/replies" + } + ] + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#sensitive": [ + { + "@value": false + } + ], + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Hashtag" + ], + "https://www.w3.org/ns/activitystreams#href": [ + { + "@id": "https://activitypub.academy/tags/tag" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "#tag" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#to": [ + { + "@id": "https://www.w3.org/ns/activitystreams#Public" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://activitypub.academy/@benules_llorvatol/112863146588107916" + } + ] + } +] diff --git a/examples/mk_like.json b/examples/mk_like.json new file mode 100644 index 0000000..fbbc3ca --- /dev/null +++ b/examples/mk_like.json @@ -0,0 +1,64 @@ +[ + { + "@id": "https://woem.men/likes/9w8zstg0gq6a0k9u", + "@type": [ + "https://www.w3.org/ns/activitystreams#Like" + ], + "https://misskey-hub.net/ns#_misskey_reaction": [ + { + "@value": ":true:" + } + ], + "https://www.w3.org/ns/activitystreams#actor": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ], + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": ":true:" + } + ], + "https://www.w3.org/ns/activitystreams#object": [ + { + "@id": "https://activitypub.academy/users/benules_llorvatol/statuses/112863519062185681" + } + ], + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@id": "https://woem.men/emojis/true", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/webp" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://woem.men/files/806c80e4-5447-49f4-bf74-a1ddffa545a0" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": ":true:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2023-12-10T09:19:13.554Z" + } + ] + } + ] + } +] diff --git a/examples/mk_note.json b/examples/mk_note.json new file mode 100644 index 0000000..7376e7d --- /dev/null +++ b/examples/mk_note.json @@ -0,0 +1,41 @@ +[ + { + "@id": "https://woem.men/notes/9ttp29lhge2u0454", + "@type": [ + "https://www.w3.org/ns/activitystreams#Note" + ], + "https://www.w3.org/ns/activitystreams#attachment": [], + "https://www.w3.org/ns/activitystreams#attributedTo": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ], + "https://www.w3.org/ns/activitystreams#cc": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/followers" + } + ], + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": "\u003cp\u003eTest post, ignore\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2024-05-28T08:22:59.861Z" + } + ], + "https://www.w3.org/ns/activitystreams#sensitive": [ + { + "@value": false + } + ], + "https://www.w3.org/ns/activitystreams#tag": [], + "https://www.w3.org/ns/activitystreams#to": [ + { + "@id": "https://www.w3.org/ns/activitystreams#Public" + } + ] + } +] diff --git a/examples/mk_note_create.json b/examples/mk_note_create.json new file mode 100644 index 0000000..fce13ff --- /dev/null +++ b/examples/mk_note_create.json @@ -0,0 +1,70 @@ +[ + { + "@id": "https://woem.men/notes/9ttp29lhge2u0454/activity", + "@type": [ + "https://www.w3.org/ns/activitystreams#Create" + ], + "https://www.w3.org/ns/activitystreams#actor": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ], + "https://www.w3.org/ns/activitystreams#cc": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/followers" + } + ], + "https://www.w3.org/ns/activitystreams#object": [ + { + "@id": "https://woem.men/notes/9ttp29lhge2u0454", + "@type": [ + "https://www.w3.org/ns/activitystreams#Note" + ], + "https://www.w3.org/ns/activitystreams#attachment": [], + "https://www.w3.org/ns/activitystreams#attributedTo": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ], + "https://www.w3.org/ns/activitystreams#cc": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/followers" + } + ], + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": "\u003cp\u003eTest post, ignore\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2024-05-28T08:22:59.861Z" + } + ], + "https://www.w3.org/ns/activitystreams#sensitive": [ + { + "@value": false + } + ], + "https://www.w3.org/ns/activitystreams#tag": [], + "https://www.w3.org/ns/activitystreams#to": [ + { + "@id": "https://www.w3.org/ns/activitystreams#Public" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#published": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2024-05-28T08:22:59.861Z" + } + ], + "https://www.w3.org/ns/activitystreams#to": [ + { + "@id": "https://www.w3.org/ns/activitystreams#Public" + } + ] + } +] diff --git a/examples/sharkey_account.json b/examples/sharkey_account.json new file mode 100644 index 0000000..1d802fe --- /dev/null +++ b/examples/sharkey_account.json @@ -0,0 +1,309 @@ +[ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5", + "@type": [ + "https://www.w3.org/ns/activitystreams#Person" + ], + "_:noindex": [ + { + "@value": false + } + ], + "http://joinmastodon.org/ns#discoverable": [ + { + "@value": true + } + ], + "http://joinmastodon.org/ns#featured": [ + { + "@value": "https://woem.men/users/9n39zo1rfckr00q5/collections/featured" + } + ], + "http://www.w3.org/2006/vcard/ns#Address": [ + { + "@value": "Freudenstadt, Germany" + } + ], + "http://www.w3.org/2006/vcard/ns#bday": [ + { + "@value": "2001-08-11" + } + ], + "http://www.w3.org/ns/ldp#inbox": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/inbox" + } + ], + "https://joinfirefish.org/ns#speakAsCat": [ + { + "@value": true + } + ], + "https://misskey-hub.net/ns#_misskey_summary": [ + { + "@value": "Checking all the boxes: Trans? :verified_trans: Gay? :queercat_sapphic: Catgirl? With added vampire :neocat_verified: Own website? May be mostly extremely bare bones, but yes While I know what I'm doing, I also don't know what I'm doing. Accidentally finding stupid behaviour in Windows since I switched to Linux DMs open One of the instance admins of woem.men, mainly responsible for emotes My pronouns page: https://en.pronouns.page/@m_evil 18+ account: @unhinged_mstar@lewd.lgbt Follow requests from empty profiles will be rejected unless I knyow you from somewhere else beforehand. Rest will be vibe checked beforehand #nobot" + } + ], + "https://misskey-hub.net/ns#isCat": [ + { + "@value": true + } + ], + "https://w3id.org/security#publicKey": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5#main-key", + "@type": [ + "https://w3id.org/security#Key" + ], + "https://w3id.org/security#owner": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5" + } + ], + "https://w3id.org/security#publicKeyPem": [ + { + "@value": "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAskGA8ejkLroxOpuj7yJn E2hpxQ876s651Wu75VAfCKpXxyzQh14i5PiJCZEPvGRsyKefKVdcIkKfoLzspqGh 4Q/W2/nbPz3UN5QdY8ayRxp9kFuDrViIKL+Xg8ftHjAuweOzg3ocg0YApbyJiJ52 2fwBQ3tZaI1rNfSxa7rYs9fTWMEIKM2fjz6PhGiTTmxer+S6gYjXsyqcd9jrAMjA E6Iw2gZmd7v1t4Fj2dGWL8kVDdOFlWkKi62nxRIVsnhr32lO9EtsT/EUiRhGqP43 A0CUhhm+kBtBx0Louqe31BJwhHy1sJXnRCs2/075ZRCXg2uH7HN7db93GruNV1Bv 9wIDAQAB -----END PUBLIC KEY----- " + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#alsoKnownAs": [ + { + "@id": "https://mk.absturztau.be/users/9gw6e1n6s2" + } + ], + "https://www.w3.org/ns/activitystreams#attachment": [ + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "\u003ca href=\"https://mstar.evilthings.de/\" rel=\"me nofollow noopener\" target=\"_blank\"\u003ehttps://mstar.evilthings.de/\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Own webpage" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "She/Her" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Pronouns" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "m_star" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Discord" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "@mstar:platypus-sandbox.com" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Matrix" + } + ] + }, + { + "@type": [ + "http://schema.org#PropertyValue" + ], + "http://schema.org#value": [ + { + "@value": "\u003ca href=\"https://gitlab.com/mstarongitlab\" rel=\"me nofollow noopener\" target=\"_blank\"\u003ehttps://gitlab.com/mstarongitlab\u003c/a\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Gitlab" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#endpoints": [ + { + "https://www.w3.org/ns/activitystreams#sharedInbox": [ + { + "@id": "https://woem.men/inbox" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#followers": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/followers" + } + ], + "https://www.w3.org/ns/activitystreams#following": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/following" + } + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#sensitive": [ + { + "@value": false + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://woem.men/files/af8da6f1-4209-4688-9038-0c3337b168e9" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers": [ + { + "@value": true + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "Melody :cat_inside:" + } + ], + "https://www.w3.org/ns/activitystreams#outbox": [ + { + "@id": "https://woem.men/users/9n39zo1rfckr00q5/outbox" + } + ], + "https://www.w3.org/ns/activitystreams#preferredUsername": [ + { + "@value": "mstar" + } + ], + "https://www.w3.org/ns/activitystreams#sharedInbox": [ + { + "@id": "https://woem.men/inbox" + } + ], + "https://www.w3.org/ns/activitystreams#summary": [ + { + "@value": "\u003cp\u003e\u003cspan\u003eChecking all the boxes:\u003cbr\u003eTrans? \u003c/span\u003e​:verified_trans:​\u003cspan\u003e\u003cbr\u003eGay? \u003c/span\u003e​:queercat_sapphic:​\u003cspan\u003e\u003cbr\u003eCatgirl? With added vampire \u003c/span\u003e​:neocat_verified:​\u003cspan\u003e\u003cbr\u003eOwn website? May be mostly extremely bare bones, but yes\u003cbr\u003e\u003cbr\u003eWhile I know what I'm doing, I also don't know what I'm doing.\u003cbr\u003eAccidentally finding stupid behaviour in Windows since I switched to Linux \u003cbr\u003eDMs open\u003cbr\u003eOne of the instance admins of woem.men, mainly responsible for emotes\u003cbr\u003e\u003cbr\u003eMy pronouns page: \u003c/span\u003e\u003ca href=\"https://en.pronouns.page/@m_evil\"\u003ehttps://en.pronouns.page/@m_evil\u003c/a\u003e\u003cspan\u003e\u003cbr\u003e\u003cbr\u003e18+ account: \u003c/span\u003e\u003ca href=\"https://woem.men/@unhinged_mstar@lewd.lgbt\" class=\"u-url mention\"\u003e@unhinged_mstar@lewd.lgbt\u003c/a\u003e\u003cspan\u003e\u003cbr\u003e\u003cbr\u003eFollow requests from empty profiles will be rejected unless I knyow you from somewhere else beforehand. Rest will be vibe checked beforehand\u003cbr\u003e\u003cbr\u003e\u003c/span\u003e\u003ca href=\"https://woem.men/tags/nobot\" rel=\"tag\"\u003e#nobot\u003c/a\u003e\u003c/p\u003e" + } + ], + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@id": "https://woem.men/emojis/cat_inside", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/png" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://woem.men/files/a53510e3-e357-470a-85f6-f839b36660a4" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": ":cat_inside:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2023-12-22T08:44:14.535Z" + } + ] + }, + { + "@id": "https://woem.men/emojis/neocat_verified", + "@type": [ + "http://joinmastodon.org/ns#Emoji" + ], + "https://www.w3.org/ns/activitystreams#icon": [ + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/png" + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://woem.men/files/20401043-8711-4421-84ec-655750588557" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": ":neocat_verified:" + } + ], + "https://www.w3.org/ns/activitystreams#updated": [ + { + "@type": "http://www.w3.org/2001/XMLSchema#dateTime", + "@value": "2023-12-25T20:11:11.884Z" + } + ] + }, + { + "@type": [ + "https://www.w3.org/ns/activitystreams#Hashtag" + ], + "https://www.w3.org/ns/activitystreams#href": [ + { + "@id": "https://woem.men/tags/nobot" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "#nobot" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://woem.men/@mstar" + } + ] + } +] diff --git a/general/createEvent.go b/general/createEvent.go new file mode 100644 index 0000000..bc79c5d --- /dev/null +++ b/general/createEvent.go @@ -0,0 +1,16 @@ +package general + +import ( + "time" + + "gitlab.com/mstarongitlab/goap" +) + +type CreateEvent struct { + Id string + Actor string + CC []string + Object goap.BaseApChain + To []string + Published time.Time +} diff --git a/general/followRequest.go b/general/followRequest.go new file mode 100644 index 0000000..9a41da4 --- /dev/null +++ b/general/followRequest.go @@ -0,0 +1,7 @@ +package general + +type FollowRequestEvent struct { + Id string + Actor string + Target string +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ec68e0e --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module gitlab.com/mstarongitlab/goap + +go 1.22.5 + +require github.com/piprate/json-gold v0.5.0 + +require ( + github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect + github.com/stretchr/testify v1.9.0 // indirect + gitlab.com/mstarongitlab/goutils v1.2.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2e9b8c5 --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/piprate/json-gold v0.5.0 h1:RmGh1PYboCFcchVFuh2pbSWAZy4XJaqTMU4KQYsApbM= +github.com/piprate/json-gold v0.5.0/go.mod h1:WZ501QQMbZZ+3pXFPhQKzNwS1+jls0oqov3uQ2WasLs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= +github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gitlab.com/mstarongitlab/goutils v1.2.0 h1:hVpc2VikWkgmX7Gbey9I72eqgmg/6GcKZ4q+M9ZBd0E= +gitlab.com/mstarongitlab/goutils v1.2.0/go.mod h1:SvqfzFxgashuZPqR9kPwQ9gFA7I1yskZjhmGmY2pAow= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/mastodon/account.go b/mastodon/account.go new file mode 100644 index 0000000..9bfc683 --- /dev/null +++ b/mastodon/account.go @@ -0,0 +1,34 @@ +package mastodon + +import ( + "time" + + "gitlab.com/mstarongitlab/goap" +) + +type Person struct { + Id string + Devices string + Discoverable bool + Featured string + FeaturedTags string + Indexable bool + Memorial bool + Inbox string + PublicKey goap.PublicKey + AlsoKnownAs string + Attachments []goap.Attachment + Endpoints map[string]string + Followers string + Following string + Icon goap.Media + Image goap.Media + ApprovesFollowers bool + Name string + Outbox string + PreferredUsername string + Published time.Time + Summary string + Tags []goap.Tag + Url string +} diff --git a/nsActivitystreams.go b/nsActivitystreams.go new file mode 100644 index 0000000..ad28da2 --- /dev/null +++ b/nsActivitystreams.go @@ -0,0 +1,100 @@ +package goap + +import ( + "time" + + "gitlab.com/mstarongitlab/goutils/sliceutils" +) + +type ActorData struct { + Next BaseApChain + Actor string +} + +func (actor *ActorData) GetSelfOrBase() (BaseApChain, bool) { + return actor.Next, true +} + +func (actor *ActorData) MarshalToMap() map[string]any { + prev := actor.Next.MarshalToMap() + prev[KEY_ACTIVITYSTREAMS_ACTOR] = strToId(actor.Actor) + return prev +} + +type ObjectData struct { + Next BaseApChain + ObjectUrl string +} + +func (object *ObjectData) GetSelfOrBase() (BaseApChain, bool) { + return object.Next, true +} + +func (object *ObjectData) MarshalToMap() map[string]any { + return appendWithKey( + object.Next.MarshalToMap(), + KEY_ACTIVITYSTREAMS_OBJECT, + strToId(object.ObjectUrl), + ) +} + +type CCData struct { + Next BaseApChain + Targets []string +} + +func (cc *CCData) GetSelfOrBase() (BaseApChain, bool) { + return cc.Next, true +} + +func (cc *CCData) MarshalToMap() map[string]any { + return appendWithKey(cc.Next.MarshalToMap(), KEY_ACTIVITYSTREAMS_CC, strsToIds(cc.Targets)) +} + +type ToData struct { + Next BaseApChain + Targets []string +} + +func (cc *ToData) GetSelfOrBase() (BaseApChain, bool) { + return cc.Next, true +} + +func (cc *ToData) MarshalToMap() map[string]any { + return appendWithKey(cc.Next.MarshalToMap(), KEY_ACTIVITYSTREAMS_TO, strsToIds(cc.Targets)) +} + +type PublishedData struct { + Next BaseApChain + Timestamp time.Time +} + +func (publisheddata *PublishedData) GetSelfOrBase() (BaseApChain, bool) { + return publisheddata.Next, true +} + +// Convert the chain to a map +// Should include the rest of the chain (extend the map the underlying object returns) +func (publisheddata *PublishedData) MarshalToMap() map[string]any { + m := publisheddata.Next.MarshalToMap() + m[KEY_ACTIVITYSTREAMS_PUBLISHED] = timeToXmlTime(publisheddata.Timestamp) + return m +} + +type TagData struct { + Next BaseApChain + Tags []Tag +} + +func (tagdata *TagData) GetSelfOrBase() (BaseApChain, bool) { + return tagdata.Next, true +} + +func (tagdata *TagData) MarshalToMap() map[string]any { + m := tagdata.Next.MarshalToMap() + m[KEY_ACTIVITYSTREAMS_TAG] = sliceutils.Map( + tagdata.Tags, + func(t Tag) map[string]any { return t.Marshal() }, + ) + return m +} diff --git a/nsAll.go b/nsAll.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsAll.go @@ -0,0 +1 @@ +package goap diff --git a/nsLitepub.go b/nsLitepub.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsLitepub.go @@ -0,0 +1 @@ +package goap diff --git a/nsMasto.go b/nsMasto.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsMasto.go @@ -0,0 +1 @@ +package goap diff --git a/nsMisskey.go b/nsMisskey.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsMisskey.go @@ -0,0 +1 @@ +package goap diff --git a/nsOstatus.go b/nsOstatus.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsOstatus.go @@ -0,0 +1 @@ +package goap diff --git a/nsSchema.go b/nsSchema.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsSchema.go @@ -0,0 +1 @@ +package goap diff --git a/nsW3.go b/nsW3.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsW3.go @@ -0,0 +1 @@ +package goap diff --git a/nsW3Security.go b/nsW3Security.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsW3Security.go @@ -0,0 +1 @@ +package goap diff --git a/nsW3Vcard.go b/nsW3Vcard.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsW3Vcard.go @@ -0,0 +1 @@ +package goap diff --git a/nsXmlschema.go b/nsXmlschema.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/nsXmlschema.go @@ -0,0 +1 @@ +package goap diff --git a/objectTypes.go b/objectTypes.go new file mode 100644 index 0000000..a8d2dd8 --- /dev/null +++ b/objectTypes.go @@ -0,0 +1 @@ +package goap diff --git a/old/actor.go b/old/actor.go new file mode 100644 index 0000000..e1e452b --- /dev/null +++ b/old/actor.go @@ -0,0 +1,34 @@ +package ap + +type MinimalActor struct { + Id string + Username string + Inbox string +} + +type MastoActor struct { + Id string + Devices MastoDevices + Discoverable MastoDiscoverable + Featured MastoFeatured + FeaturedTags MastoFeaturedTags + Indexable MastoIndexable + Memorial MastoMemorial + Inbox W3Inbox + PublicKey W3SecurityPublicKey + AlsoKnownAs ActivityStreamsAlsoKnownAs + Attachments []ActivityStreamsAttachment + Endpoints []map[string]IdType + Followers ActivityStreamsFollowers + Following ActivityStreamsFollowing + Icon ActivityStreamsIcon + Image ActivityStreamsImage + RestrictedFollow ActivityStreamsRestrictedFollow + Name ActivityStreamsName + Outbox ActivityStreamsOutbox + PrefferedUsername ActivityStreamsPrefferedUsername + Published ActivityStreamsPublished + Summary ActivityStreamsSummary + Tags []ActivityStreamsTag + Url ActivityStreamsUrl +} diff --git a/old/checkHeader.go b/old/checkHeader.go new file mode 100644 index 0000000..5c09332 --- /dev/null +++ b/old/checkHeader.go @@ -0,0 +1,24 @@ +package ap + +import "strings" + +// Header used for making requests for AP resources +// Not used yet +const OUTBOUND_REQUEST_HEADER = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1" + +var contentHeadersToCheck = []string{ + "application/json", + "application/ld+json", +} + +// Check a given string if it contains any of the content types specified in +// the contentHeadersToCheck slice +// Used for differentiating requests for the ActivityPub version of some data vs frontend version +func ContainsApContentHeader(toCheck string) bool { + for _, h := range contentHeadersToCheck { + if strings.Contains(toCheck, h) { + return true + } + } + return false +} diff --git a/old/common_types.go b/old/common_types.go new file mode 100644 index 0000000..bb500a9 --- /dev/null +++ b/old/common_types.go @@ -0,0 +1,18 @@ +package ap + +import "net/url" + +type IdType struct { + Id *url.URL +} + +type ValueType[T any] struct { + Value T +} + +type Media struct { + Type url.URL + MediaType *ValueType[string] + Url IdType + Sensitive *ValueType[bool] +} diff --git a/old/constants.go b/old/constants.go new file mode 100644 index 0000000..4775255 --- /dev/null +++ b/old/constants.go @@ -0,0 +1,81 @@ +package ap + +const ( + KEY_ID = "@id" // Value of type string + KEY_TYPE = "@type" // Value of type string slice / activitystreams object url slice + KEY_VALUE = "@value" // Could be any type really +) + +const ( + KEY_MASTO_DEVICES = "http://joinmastodon.org/ns#devices" // No idea what this is, but Masto includes it + KEY_MASTO_DISCOVERABLE = "http://joinmastodon.org/ns#discoverable" // iirc this is whether the object can be found by crawlers + KEY_MASTO_FEATURED = "http://joinmastodon.org/ns#featured" // Users tagged? I think + KEY_MASTO_FEATURED_TAGS = "http://joinmastodon.org/ns#featuredTags" // Hashtags included, I think + KEY_MASTO_INDEXABLE = "http://joinmastodon.org/ns#indexable" // Is the object crawlable round 2 + KEY_MASTO_MEMORIAL = "http://joinmastodon.org/ns#memorial" // Account dead and disabled? +) + +const ( + KEY_W3_INBOX = "http://www.w3.org/ns/ldp#inbox" // Where to send activities to + KEY_W3_SECURITY_PUBLICKEY = "https://w3id.org/security#publicKey" // Public key of the account + KEY_W3_SECURITY_OWNER = "https://w3id.org/security#owner" // Owner of the public key + KEY_W3_SECURITY_PUBLICKEYPEM = "https://w3id.org/security#publicKeyPem" // Pem content of the key + KEY_W3_VCARD_ADRESS = "http://www.w3.org/2006/vcard/ns#Address" // Vcard address of an account + KEY_W3_VCARD_BIRTHDAY = "http://www.w3.org/2006/vcard/ns#bday" // Vcard birthday of an account +) + +const ( + KEY_ACTIVITYSTREAMS_ALSOKNOWNAS = "https://www.w3.org/ns/activitystreams#alsoKnownAs" // Lists of usernames? + KEY_ACTIVITYSTREAMS_ATTACHMENTS = "https://www.w3.org/ns/activitystreams#attachment" // Attached elements like emotes and hashtags + KEY_ACTIVITYSTREAMS_NAME = "https://www.w3.org/ns/activitystreams#name" // AP name + KEY_ACTIVITYSTREAMS_ENDPOINTS = "https://www.w3.org/ns/activitystreams#endpoints" // list of assocciated endpoints + KEY_ACTIVITYSTREAMS_SHAREDINBOX = "https://www.w3.org/ns/activitystreams#sharedInbox" // Link to the shared inbox of the server + KEY_ACTIVITYSTREAMS_FOLLOWERS = "https://www.w3.org/ns/activitystreams#followers" // Who is following the account + KEY_ACTIVITYSTREAMS_FOLLOWING = "https://www.w3.org/ns/activitystreams#following" // Who is this account following + KEY_ACTIVITYSTREAMS_ICON = "https://www.w3.org/ns/activitystreams#icon" // User icon + KEY_ACTIVITYSTREAMS_MEDIATYPE = "https://www.w3.org/ns/activitystreams#mediaType" // What type of media is this? Example image/jpeg + KEY_ACTIVITYSTREAMS_URL = "https://www.w3.org/ns/activitystreams#url" // Some url + KEY_ACTIVITYSTREAMS_IMAGE = "https://www.w3.org/ns/activitystreams#image" // Account banner + KEY_ACTIVITYSTREAMS_RESTRICTED_FOLLOW = "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers" // Does the account manually approve follow requests + KEY_ACTIVITYSTREAMS_OUTBOX = "https://www.w3.org/ns/activitystreams#outbox" // Link to the account's outbox + KEY_ACTIVITYSTREAMS_PREFFEREDUSERNAME = "https://www.w3.org/ns/activitystreams#preferredUsername" // What the shown username is + KEY_ACTIVITYSTREAMS_PUBLISHED = "https://www.w3.org/ns/activitystreams#published" // When an object was created + KEY_ACTIVITYSTREAMS_SUMMARY = "https://www.w3.org/ns/activitystreams#summary" // Summary of an account + KEY_ACTIVITYSTREAMS_TAG = "https://www.w3.org/ns/activitystreams#tag" // A tag, no idea what those are + KEY_ACTIVITYSTREAMS_CC = "https://www.w3.org/ns/activitystreams#cc" // Urls also included in the object + KEY_ACTIVITYSTREAMS_TO = "https://www.w3.org/ns/activitystreams#to" // Urls to send an activity to + KEY_ACTIVITYSTREAMS_OBJECT = "https://www.w3.org/ns/activitystreams#object" // Object url and sometimes value + + // Object types (I think) + // Those are values the object type can have + + KEY_ACTIVITYSTREAMS_ACTOR = "https://www.w3.org/ns/activitystreams#actor" + KEY_ACTIVITYSTREAMS_FOLLOW = "https://www.w3.org/ns/activitystreams#Follow" // Object is an activity of type follow + KEY_ACTIVITYSTREAMS_PERSON = "https://www.w3.org/ns/activitystreams#Person" // Object is of type Person + KEY_ACTIVITYSTREAMS_CREATE = "https://www.w3.org/ns/activitystreams#Create" // Object is an activity of type Create + + KEY_ACTIVITYSTREAMS_OAUTHAUTHORIZATION = "https://www.w3.org/ns/activitystreams#oauthAuthorizationEndpoint" // Endpoint url for oauth login? + KEY_ACTIVITYSTREAMS_OAUTHTOKEN = "https://www.w3.org/ns/activitystreams#oauthTokenEndpoint" // Endpoint url for oauth token verification? + KEY_ACTIVITYSTREAMS_UPLOADMEDIA = "https://www.w3.org/ns/activitystreams#uploadMedia" // Endpoint url to upload media to? +) + +const ( + KEY_SCHEMA_VALUE = "http://schema.org#value" // The value for some field +) + +const ( + KEY_MISSKEY_MKSUMMARY = "https://misskey-hub.net/ns#_misskey_summary" // Misskey specific formatted summary + KEY_MISSKEY_ISCAT = "https://misskey-hub.net/ns#isCat" // Does the account identify as cat? + KEY_FIREFISH_SPEAKASCAT = "https://joinfirefish.org/ns#speakAsCat" // Does the account speak like a cat? +) + +const ( + KEY_LITEPUB_CAPABILITIES = "http://litepub.social/ns#capabilities" + KEY_LITEPUB_OAUTHREGISTRATION = "http://litepub.social/ns#oauthRegistrationEndpoint" +) + +const ( + KEY_MYSTERIOUS_NOINDEX = "_:noindex" + KEY_MYSTERIOUS_BACKGROUNDURL = "_:backgroundUrl" + KEY_MYSTERIOUS_FEATURED = "_:featured" +) diff --git a/old/context.go b/old/context.go new file mode 100644 index 0000000..71f4a4f --- /dev/null +++ b/old/context.go @@ -0,0 +1,49 @@ +package ap + +// Just steal this one from sharkey +// Also use this one for all AP objects for now +// Can make a function to extract context from an expanded object later +// TODO: Consider if such a function is worth it or if it would hinder learning +var allContext = map[string]any{ + "@context": []any{ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + map[string]any{ + "fedibird": "http://fedibird.com/ns#", + "toot": "http://joinmastodon.org/ns#", + "schema": "http://schema.org#", + "misskey": "https://misskey-hub.net/ns#", + "firefish": "https://joinfirefish.org/ns#", + "sharkey": "https://joinsharkey.org/ns#", + "vcard": "http://www.w3.org/2006/vcard/ns#", + + "Key": "sec:Key", + + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "Hashtag": "as:Hashtag", + "quoteUrl": "as:quoteUrl", + + "quoteUri": "fedibird:quoteUri", + + "Emoji": "toot:Emoji", + "featured": "toot:featured", + "discoverable": "toot:discoverable", + + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + + "_misskey_content": "misskey:_misskey_content", + "_misskey_quote": "misskey:_misskey_quote", + "_misskey_reaction": "misskey:_misskey_reaction", + "_misskey_votes": "misskey:_misskey_votes", + "_misskey_summary": "misskey:_misskey_summary", + "isCat": "misskey:isCat", + + "speakAsCat": "firefish:speakAsCat", + + "backgroundUrl": "sharkey:backgroundUrl", + "listenbrainz": "sharkey:listenbrainz", + }, + }, +} diff --git a/old/explicit_types.go b/old/explicit_types.go new file mode 100644 index 0000000..49bc2a9 --- /dev/null +++ b/old/explicit_types.go @@ -0,0 +1,61 @@ +package ap + +import ( + "net/url" + "time" +) + +type ( + ActivityStreamsAlsoKnownAs IdType + ActivityStreamsAttachment struct { + Type *url.URL + Value ValueType[string] + Name ValueType[string] + } + ActivityStreamsSharedInbox IdType + ActivityStreamsFollowers IdType + ActivityStreamsFollowing IdType + ActivityStreamsImage Media + ActivityStreamsIcon Media + ActivityStreamsRestrictedFollow ValueType[bool] + ActivityStreamsName ValueType[string] + ActivityStreamsOutbox IdType + ActivityStreamsPrefferedUsername ValueType[string] + ActivityStreamsPublished struct { + Type string + Value time.Time + } + ActivityStreamsSummary ValueType[string] + ActivityStreamsUrl IdType + // NOTE: Technically can contain a lot more values, but tags are not consistent in what those are. Only consistent one is the type + + ActivityStreamsTag struct { + Type string + } + ActivityStreamsTo IdType + ActivityStreamsCC IdType + + ActivityStreamsActor IdType + // NOTE: Technically, objects can have a LOT of data. I don't care. Treat them as ID type + // Just fetch whatever the ID is later on separately and throw away anything else but the ID + ActivityStreamsObject IdType + ActivityStreamsFollow IdType +) + +type ( + MastoDevices IdType + MastoDiscoverable ValueType[bool] + MastoFeatured IdType + MastoFeaturedTags IdType + MastoIndexable ValueType[bool] + MastoMemorial ValueType[bool] +) + +type ( + W3Inbox IdType + W3SecurityPublicKey struct { + Id *url.URL + Owner *url.URL + KeyPem string + } +) diff --git a/old/parser.go b/old/parser.go new file mode 100644 index 0000000..36c32ac --- /dev/null +++ b/old/parser.go @@ -0,0 +1,58 @@ +package ap + +import ( + "encoding/json" + "fmt" + "net/url" + + "github.com/piprate/json-gold/ld" +) + +type ApThing map[string]any + +type RemoteDocumentLoader struct{} + +var ldOpts = ld.NewJsonLdOptions("") +var ldProcessor = ld.NewJsonLdProcessor() + +// Try and parse a remote ActivityPub object into a more usable form +// Result is a map[string]any where the keys defined in /ap/constants.go should be usable, +// depending on the type of object +// The general approach for fetching an object will be to fetch the main object +// and only store the ID for sub-objects to fetch them later +func ParseFromUrl(u *url.URL) (ApThing, error) { + // TODO: Add custom document parser (copy default implementation) that includes verification + + // Explanation: + // Expansion removes the context from a document (json-ld activitypub data) + // and turns every field into something along the lines of + // "https://example.com/ns#ObjectType": + // This makes it easier to deal with things as they now have a very consistent naming scheme + // See /ap/constants.go for those + + parsed, err := ldProcessor.Expand(u.String(), ldOpts) + if err != nil { + return nil, fmt.Errorf("failed to process remote document: %w", err) + } + if len(parsed) == 0 { + return nil, fmt.Errorf("document has a length of 0") + } + typed, ok := parsed[0].(ApThing) + if !ok { + return nil, fmt.Errorf("couldn't cast data to ApThing") + } + return typed, nil +} + +// Compact an AP object down into a compressed json-ld form +// That compacted form should be accepted by all AP servers +// It also handles context for any fields +// Content should only use keys defined in /ap/constants.go though +// Other things might get lost in translation +func Compact(content map[string]any) ([]byte, error) { + res, err := ldProcessor.Compact(content, allContext, ldOpts) + if err != nil { + return nil, fmt.Errorf("failed to compact data: %w", err) + } + return json.Marshal(res) +} diff --git a/old/type_parsers.go b/old/type_parsers.go new file mode 100644 index 0000000..aea5269 --- /dev/null +++ b/old/type_parsers.go @@ -0,0 +1,172 @@ +package ap + +import ( + "net/url" + "time" +) + +// Try and parse a value into an IdType +// Returns nil if failed +func TryParseIdType(rawIn any) *IdType { + switch in := rawIn.(type) { + case []any: + if len(in) == 0 { + return nil + } + m, ok := in[0].(map[string]any) + if !ok { + return nil + } + return TryParseIdType(m) + case map[string]any: + vRaw, ok := in[KEY_ID] + if !ok { + return nil + } + v, ok := vRaw.(string) + if !ok { + return nil + } + u, err := url.Parse(v) + if err != nil { + return nil + } + return &IdType{ + Id: u, + } + default: + return nil + } +} + +func TryParseValueType[T any](rawIn any) *ValueType[T] { + switch in := rawIn.(type) { + case map[string]any: + vRaw, ok := in[KEY_ID] + if !ok { + return nil + } + v, ok := vRaw.(T) + if !ok { + return nil + } + return &ValueType[T]{ + Value: v, + } + case []any: + if len(in) == 0 { + return nil + } + v, ok := in[0].(map[string]any) + if !ok { + return nil + } + return TryParseValueType[T](v) + default: + return nil + } +} + +func TryParseActivityStreamsPublicKey(rawIn any) *W3SecurityPublicKey { + switch in := rawIn.(type) { + case map[string]any: + asIdType := TryParseIdType(in) + if asIdType == nil { + return nil + } + ownerType := TryParseIdType(in[KEY_W3_SECURITY_OWNER]) + if ownerType == nil { + return nil + } + keyValue := TryParseValueType[string](in[KEY_W3_SECURITY_PUBLICKEYPEM]) + if keyValue == nil { + return nil + } + return &W3SecurityPublicKey{ + Id: asIdType.Id, + Owner: ownerType.Id, + KeyPem: keyValue.Value, + } + case []any: + if len(in) == 0 { + return nil + } + return TryParseActivityStreamsPublicKey(in[0]) + default: + return nil + } +} + +func TryParseActivityStreamsAttachment(rawIn any) *ActivityStreamsAttachment { + switch in := rawIn.(type) { + case []any: + if len(in) == 0 { + return nil + } + return TryParseActivityStreamsAttachment(in[0]) + case map[string]any: + rawType, ok := in[KEY_TYPE] + if !ok { + return nil + } + strType, ok := rawType.(string) + if !ok { + return nil + } + urlType, err := url.Parse(strType) + if err != nil { + return nil + } + value := TryParseValueType[string](in[KEY_SCHEMA_VALUE]) + if value == nil { + return nil + } + name := TryParseValueType[string](in[KEY_ACTIVITYSTREAMS_NAME]) + if name == nil { + return nil + } + return &ActivityStreamsAttachment{ + Type: urlType, + Name: *name, + Value: *value, + } + default: + return nil + } +} + +func TryParseActivityStreamsPublished(rawIn any) *ActivityStreamsPublished { + switch in := rawIn.(type) { + case []any: + if len(in) == 0 { + return nil + } + return TryParseActivityStreamsPublished(in[0]) + case map[string]any: + rawType, ok := in[KEY_TYPE] + if !ok { + return nil + } + strType, ok := rawType.(string) + if !ok { + return nil + } + value := TryParseValueType[string](in) + tv, err := time.Parse("2006-01-02T04:05:06Z", value.Value) + if err != nil { + return nil + } + return &ActivityStreamsPublished{ + Type: strType, + Value: tv, + } + default: + return nil + } +} + +// NOTE: Since I do not know if tags are consistent with the struct yet, +// This funtion does not do anything yet and should not be used +func TryParseActivityStreamsTag(rawIn any) *ActivityStreamsTag { + return nil +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..57ea5f4 --- /dev/null +++ b/utils.go @@ -0,0 +1,33 @@ +package goap + +import ( + "time" + + "gitlab.com/mstarongitlab/goutils/other" + "gitlab.com/mstarongitlab/goutils/sliceutils" +) + +func appendWithKey(toAppend map[string]any, key string, val any) map[string]any { + toAppend[key] = val + return toAppend +} + +// Returns an array of IdValues since that's what is expected for compression of the map later on +func strToId(str string) []IdValue { + return []IdValue{{Id: str}} +} + +func strsToIds(strs []string) []IdValue { + return sliceutils.Map(strs, func(s string) IdValue { + return IdValue{Id: s} + }) +} + +// Returns an array of values since that's what expected for compression later on +func timeToXmlTime(t time.Time) []ValueValue[string] { + return []ValueValue[string]{ + { + Type: other.IntoPointer(KEY_XMLSCHEMA_DATETIME), + Value: t.Format("2006-01-02T15:04:05.000Z"), + }} +} diff --git a/variousTypes.go b/variousTypes.go new file mode 100644 index 0000000..1c89323 --- /dev/null +++ b/variousTypes.go @@ -0,0 +1,72 @@ +package goap + +type PublicKey struct { + Id string + Owner string + Pem string +} + +type Attachment struct { + Type string + Value string + Name string +} + +type Media struct { + Type string + MediaType string + Url string +} + +type Tag struct { + Type string + Href string + Name string +} + +type IdValue struct { + Id string +} + +type ValueValue[T any] struct { + Type *string + Value T +} + +func (p PublicKey) Marshal() map[string]any { + return map[string]any{ + KEY_ID: p.Id, + KEY_W3_SECURITY_OWNER: IdValue{Id: p.Owner}.Marshal(), + } +} + +func (a Attachment) Marshal() map[string]any { + return map[string]any{ + KEY_TYPE: []string{KEY_SCHEMA_PROPERTYVALUE}, + KEY_SCHEMA_VALUE: ValueValue[string]{Value: a.Value}.Marshal(), + } +} + +func (t Tag) Marshal() map[string]any { + return map[string]any{ + KEY_TYPE: t.Type, + KEY_ACTIVITYSTREAMS_NAME: t.Name, + KEY_ACTIVITYSTREAMS_HREF: IdValue{Id: t.Href}.Marshal(), + } +} + +func (i IdValue) Marshal() map[string]any { + return map[string]any{ + KEY_ID: i.Id, + } +} + +func (v ValueValue[T]) Marshal() map[string]any { + m := map[string]any{ + KEY_VALUE: v.Value, + } + if v.Type != nil { + m[KEY_TYPE] = *v.Type + } + return m +}