I Guess I’m now the first ever Indiekit Instance on the #fediverse
Thanks to Fedify
{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" ], "type": "Person", "id": "https://rmendes.net/", "preferredUsername": "rick", "name": "Ricardo Mendes", "url": "https://rmendes.net/", "inbox": "https://rmendes.net/activitypub/inbox", "outbox": "https://rmendes.net/activitypub/outbox", "followers": "https://rmendes.net/activitypub/followers", "following": "https://rmendes.net/activitypub/following", "publicKey": { "id": "https://rmendes.net/#main-key", "owner": "https://rmendes.net/", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4F2MDzCr5lYiI9LSFpf4\nsysMIQK63Po5FkVPKzfQSdxHJjYEFqniKRHa+gpQzg0aadSWMIsBbZWvVKypKZZR\nd3g3LDvtV6zyCOdQ0XUxp4ggYmvj22VcdZkyeygMSxkl9D8zr6U5TzAEfPYBMUMx\nwruTUAAFpyLQTCQmSCcMllxlPvgeHCF54VYg8QArTvvYz9G7IMsjR1OWM1AAg2Iy\n1UevOPBLVdSt2SBYf1GccsLjHEwgPTFT2iBtE2FTwlVgthOpEG5imB1Up0G1gZtA\nA5RCG1nR9ymRCFpDfg5Awtx+vtNCQ64guM1yjMeKEk7KJoULWqF2O+iEzvyR/BPq\n8QIDAQAB\n-----END PUBLIC KEY-----\n" }, "summary": "Personal website of Ricardo Mendes", "icon": { "type": "Image", "url": "https://rmendes.net/images/user/avatar.jpg" }, "alsoKnownAs": [ "https://mstdn.social/users/rmdes" ] }[...]
{
"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],
"id":"https://pub.saar.social/user/achim/key",
"type":"Key",
"publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBI[...]IDAQAB\n-----END PUBLIC KEY-----\n",
"owner":"https://pub.saar.social/user/achim"
}
But my follow http call gets this back from Mastodon:
{"error":"Unable to fetch key JSON at https://pub.saar.social/user/achim/key"}
Can somebody give me a hint how to figure out what the problem is?
@silverpill it looks like my mitra instance cannot follow the relay using AodeRelay. I see some error messages in the logs.
Oct 12 05:03:03 grassland mitra[1880146]: 2025-10-12T05:03:03 mitra_activitypub::queues [INFO] delivering activity to 1 inboxes: {"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://w3id.org/security/data-integrity/v1",{"Emoji":"toot:Emoji","EmojiReact":"litepub:EmojiReact","Hashtag":"as:Hashtag","litepub":"http://litepub.social/ns#","sensitive":"as:sensitive","toot":"http://joinmastodon.org/ns#"}],"actor":"https://moon.lonewolf.zone/users/followbot","id":"https://moon.lonewolf.zone/activities/follow/0199d655-f659-3d21-bd61-1fd771736447","object":"https://relay.synth.download/actor","proof":{"created":"2025-10-12T02:53:01.917253640Z","cryptosuite":"eddsa-jcs-2022","proofPurpose":"assertionMethod","proofValue":"z2xPPCkL8WiCDZu7BcFMJpMZVFtgDMZk8V5ysvDYyxNdnx3N8e4VCA8eYPAa6X8HKWaPNEkiPBAWWk4jGaQimErVa","type":"DataIntegrityProof","verificationMethod":"https://moon.lonewolf.zone/users/followbot#ed25519-key"},"to":["https://relay.synth.download/actor"],"type":"Follow"} Oct 12 05:03:13 grassland mitra[1880146]: 2025-10-12T05:03:13 mitra_activitypub::deliverer [WARN] failed to deliver activity to https://relay.synth.download/inbox: error sending request for url (https://relay.synth.download/inbox): operation timed outsometimes it returns 400 error.
Oct 12 05:02:35 v2202502232422317350 mitra[1880146]: 2025-10-12T05:02:35 mitra_activitypub::deliverer [WARN] failed to deliver activity to https://relay.synth.download/inbox: HTTP error 400: [400]次のような未知のJSONがソフトウェアに与えられたとき、
{
"name": "Alice"
}
ソフトウェアは"Alice"という値がなんであるかを識別することはできません。よって、nameという文字列キーの代わりに事前に定義された識別子を用いることにしましょう。例えば:
{
"http://xmlns.com/foaf/0.1/name": "Alice"
}
(URLとして解釈可能な文字列ではありますが、これはたまたまです。URLとして機能するわけではありません。便宜上このような文字列を使っているというだけ。ですのでそのURLのドメインが悪意ある第三者によって詐欺サイトにリダイレクトするようになっていても、JSON-LD的には問題ありません!)
ここで、互換性のため@contextというものを考えたいと思います。これを使って次のように書くと、
{
"@context": {
"name": "http://xmlns.com/foaf/0.1/name"
},
"name": "Alice"
}
@contextを無視するだけで、従来のソフトウェアは今まで通りにJSONを扱うことができます。これがJSON-LDの基本的なコンセプトです。
ちなみに@contextではあらゆる識別子をあらゆる文字列へマッピングできます。よって、ソフトウェアは次の2種類のJSON-LDを同じように解釈する必要がありますね!
{
"@context": {
"name": "http://xmlns.com/foaf/0.1/name"
},
"name": "Alice"
}{
"@context": {
"名前": "http://xmlns.com/foaf/0.1/name"
},
"名前": "Alice"
}
ではここでさらなる抽象化を考えてみましょう。次のようにすると、与えられたJSON-LDが人物の情報であることを表すことができます。
{
"@context": "https://json-ld.org/contexts/person.jsonld",
"name": "Alice"
}
コンテキストは複数指定することもできますし、従来の辞書型と混ぜることもできます。さらに、あるコンテキストで定義されたキーに別名を付けて使うこともできます。
{
"@context": [
"https://example.com/foo",
"https://example.com/bar",
{
"buz": "https://example.com/buz",
"qux": "buz:qux"
}
]
}
そうそう、クラス定義というものもあります。次の例における"Object"という文字列値は、Activity Vocabulary(ActiviyPubを構成する仕様の一つ)におけるObjectというクラスであることを示すものです。
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Object",
"id": "http://www.test.example/object/1",
"name": "A Simple, non-specific object"
}
Objectという文字列がキーとして使われることがないことはJSON-LDからは読み取れませんが、まあなんとかしてください!
ちなみにMisskeyが送信するJSONに付与する@contextは次の通り。つまり、このコンテキストを理解できるソフトウェアを作れば、Misskeyと連携することができるということです。
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"Key": "sec:Key",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"sensitive": "as:sensitive",
"Hashtag": "as:Hashtag",
"quoteUrl": "as:quoteUrl",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji",
"featured": "toot:featured",
"discoverable": "toot:discoverable",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"misskey": "https://misskey-hub.net/ns#",
"_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",
"vcard": "http://www.w3.org/2006/vcard/ns#"
}
]
}
(ですがMisskeyは受信したJSON-LDをただのJSONとして解釈し、@contextの内容は関知しません。)
そもそも情報交換用のサーバ間APIでJSON-LDのような柔軟で既存のJSON構造を壊さずに導入できる仕様を使う必要はないかもしれませんが……まあ細かいことは気にしない!
それでは、楽しいActivityPubサーバ開発を!!!
This is an activity I received:
{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://www.w3.org/ns/did/v1","https://w3id.org/security/multikey/v1","https://w3id.org/security/data-integrity/v1","https://w3id.org/fep/c390",{"Category":"nomad:Category","Hashtag":"as:Hashtag","Sync":"nomad:Sync","canReply":"toot:canReply","canSearch":"nomad:canSearch","collectionOf":"nomad:collectionOf","contextHistory":{"@container":"@list","@id":"https://w3id.org/fep/171b/contextHistory","@type":"@id"},"copiedTo":"nomad:copiedTo","directMessage":"nomad:directMessage","discoverable":"toot:discoverable","expires":"nomad:expires","gateways":{"@container":"@list","@id":"https://w3id.org/fep/ef61/gateways","@type":"@id"},"indexable":"toot:indexable","joinMode":"https://w3id.org/fep/8a8e/joinMode","manuallyApprovesFollowers":"as:manuallyApprovesFollowers","movedTo":"as:movedTo","nomad":"https://macgirvin.com/apschema#","oauthRegistrationEndpoint":"nomad:oauthRegistrationEndpoint","openWebAuth":"nomad:openWebAuth","owaRedirect":"nomad:owaRedirect","permissions":"nomad:permissions","searchContent":"nomad:searchContent","searchTags":"nomad:searchTags","sensitive":"as:sensitive","timezone":"http://www.w3.org/2006/time#timezone","toot":"http://joinmastodon.org/ns#","webfinger":{"@id":"wf:webfinger","@type":"xsd:string"},"wf":"https://purl.archive.org/socialweb/webfinger#","xsd":"http://www.w3.org/2001/XMLSchema#"}],"actor":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor","cc":[],"context":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","contextHistory":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","directMessage":true,"id":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/activity/3f3e6efe-9bac-425d-9692-4df179937c5f","object":{"attributedTo":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor","canReply":["https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor/followers"],"cc":[],"content":"@!<span class=\"h-card\"><a class=\"u-url mention\" href=\"https://mitra.social/users/silverpill\" target=\"_blank\" rel=\"nofollow noopener\" >silverpill@mitra.social</a></span> Here's an activity that should be signed with RFC9421.","context":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","contextHistory":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","directMessage":true,"id":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/item/3f3e6efe-9bac-425d-9692-4df179937c5f","proof":{"created":"2025-06-09T21:22:04Z","cryptosuite":"eddsa-jcs-2022","proofPurpose":"assertionMethod","proofValue":"zcxM3mfRbyXsbNx3YZypxjMPhVxcBuyo6Lz6ZUz9hmHaEok7mfG9Db9oA8uz9LWzF7EZnHHKKBn5UuM81FNmXPDo","type":"DataIntegrityProof","verificationMethod":"did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk"},"published":"2025-06-09T21:22:04Z","replies":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/replies/3f3e6efe-9bac-425d-9692-4df179937c5f","source":{"content":"@![url=https://mitra.social/users/silverpill]silverpill[/url] Here's an activity that should be signed with RFC9421.","mediaType":"text/x-multicode"},"tag":[{"href":"https://mitra.social/users/silverpill","name":"@silverpill@mitra.social","type":"Mention"}],"to":["https://mitra.social/users/silverpill"],"type":"Note","url":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/item/3f3e6efe-9bac-425d-9692-4df179937c5f"},"proof":{"created":"2025-06-09T21:22:05Z","cryptosuite":"eddsa-jcs-2022","proofPurpose":"assertionMethod","proofValue":"z5tDnWHWDj2JyaA3CHAcDe3Qy3K77HtSMrAGsucSk6pbp3bsbuUU8cZR5NkQyfE273JgT9FwYaCrtTAXUN4oJocNQ","type":"DataIntegrityProof","verificationMethod":"did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk"},"published":"2025-06-09T21:22:04Z","tag":[{"href":"https://mitra.social/users/silverpill","name":"@silverpill@mitra.social","type":"Mention"}],"target":{"attributedTo":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor","id":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","type":"Collection"},"to":["https://mitra.social/users/silverpill"],"type":"Create","url":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/activity/3f3e6efe-9bac-425d-9692-4df179937c5f"}I can verify the activity, but not its object.
Canonicalized object (with proof taken out):
{"attributedTo":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor","canReply":["https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/actor/followers"],"cc":[],"content":"@!<span class=\"h-card\"><a class=\"u-url mention\" href=\"https://mitra.social/users/silverpill\" target=\"_blank\" rel=\"nofollow noopener\" >silverpill@mitra.social</a></span> Here's an activity that should be signed with RFC9421.","context":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","contextHistory":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/conversation/history/3f3e6efe-9bac-425d-9692-4df179937c5f","directMessage":true,"id":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/item/3f3e6efe-9bac-425d-9692-4df179937c5f","published":"2025-06-09T21:22:04Z","replies":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/replies/3f3e6efe-9bac-425d-9692-4df179937c5f","source":{"content":"@![url=https://mitra.social/users/silverpill]silverpill[/url] Here's an activity that should be signed with RFC9421.","mediaType":"text/x-multicode"},"tag":[{"href":"https://mitra.social/users/silverpill","name":"@silverpill@mitra.social","type":"Mention"}],"to":["https://mitra.social/users/silverpill"],"type":"Note","url":"https://macgirvin.com/.well-known/apgateway/did🔑z6MkhPXNfiHDh2qSNjFzZ9yY27C1iHnHVbb1eaxuoiEe4tjk/item/3f3e6efe-9bac-425d-9692-4df179937c5f"}Signature base (object and proof config hashes):
3e51edddfe2378d071b6a79f091150b035045e80d053ce180893f000c5fba50197b90ed2cf47016298ae77a9a8572ba32c39e0570aa31c85033f54525af733bb↓こういうActor情報を吐いてるんだけど、なんかおかしいところありそうですかね
{ "discoverable": true, "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1" ], "id": "https://siren.capslock.dev/actor", "name": "田舎の昼のサイレンbot", "preferredUserName": "siren", "summary": "<p>田舎の昼のサイレンbotをActivityPubでも実現しようというハイ・テックなこころみです。</p><p>元bot様とは何ら関係がありません。現在作りかけなので動作していません</p>", "type": "Person", "inbox": "https://siren.capslock.dev/inbox", "sharedInbox": "https://siren.capslock.dev/inbox", "outbox": "https://siren.capslock.dev/outbox", "publicKey": { "id": "https://siren.capslock.dev/actor#main-key", "owner": "https://siren.capslock.dev/actor", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAryP6P3P4X1qNJAIyg9Q4\neAJdzdMBD7oFPqqsyurnWskvCMeljM6sxoohnrVEjD10NZirnyt7X/cpYSc5BMGk\nwIfTWyhTMYbNTXlrV0yFrsBtv39tG5TcEWdX1+NvMn68MsCkLv7h/qsz4rBVxmmf\nc0lpz9KCqv1AI3mSuJYVNEXP59QuoP0jqtxE2e4Man4hp/BU26XBJJ8i/ZshrXtb\n3/3A7K60cYjCboTDwCzD4TYuxgwx0Jgk28zlTYM1NuQNYehpgd5mviUXdFdWatuP\nWSuAjGu0T6RNMWTcUh0cV39+wr1fKtZ9rHPubxXz7eikOGvjbB8UIDjXG5Kh7Xv3\nWwIDAQAB\n-----END PUBLIC KEY-----\n", "type": "Key" } }GNU social JP is a social network, courtesy of GNU social JP管理人. It runs on GNU social, version 2.0.2-dev, available under the GNU Affero General Public License.
All GNU social JP content and data are available under the Creative Commons Attribution 3.0 license.