<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>House of Nettles: #mastodon</title>
  <id>https://nex-3.com/tag/mastodon/</id>
  <link href="https://nex-3.com/tag/mastodon/feed.xml" rel="self"/>
  <link href="https://nex-3.com/tag/mastodon/" />
  <updated>2024-10-28T00:36:43Z</updated>
    <entry>
      <title>How to fail to read a Fediverse post</title>
      <link href="https://nex-3.com/blog/so-im-trying-to-add-support/" rel="alternate"/>
      <id>https://nex-3.com/blog/so-im-trying-to-add-support/</id>
      <published>2024-10-28T00:36:43Z</published>
      <updated>2024-10-28T00:51:18Z</updated>
      <author><name>Natalie Weizenbaum</name>
          <uri>https://nex-3.com/</uri></author><category term="meta" label="meta"/><category term="code" label="code"/><category term="mastodon" label="mastodon"/><content type="html">&lt;p&gt;So I&#39;m trying to add support for automatically embedding Fediverse posts on this
blog, right? And yeah I could use the Mastodon API for it, but I&#39;d really rather
be able to make it work with &lt;em&gt;anything&lt;/em&gt; that speaks ActivityPub. So okay, I look
up &lt;a href=&#34;https://www.w3.org/TR/activitypub/&#34;&gt;the ActivityPub spec&lt;/a&gt;. It&#39;s a bit confusing, but I figure out how to at make
a GET request for an ActivityPub resource: just add &lt;code&gt;Content-Type: application/ld+json; profile=&amp;quot;https://www.w3.org/ns/activitystreams&amp;quot;&lt;/code&gt;. I can
even make a request for one of my statuses and it works! Fantastic!&lt;/p&gt;
&lt;p&gt;Just to verify, I make a request to another server, and that&#39;s where things
start getting hairy. Instead of a nice JSON representation of the post, I get
back a 401 Unauthorized with a body that says &amp;quot;Request not signed&amp;quot;. This is a
public post, but after some digging it turns out Mastodon (and by extension
ActivityPub as a whole) has a &lt;a href=&#34;https://docs.joinmastodon.org/spec/security/#http&#34;&gt;&amp;quot;secure mode&amp;quot;&lt;/a&gt; where &lt;em&gt;all&lt;/em&gt; requests have to be
signed.&lt;/p&gt;
&lt;p&gt;Signed by what though? This is a distributed system—there&#39;s no central authority
to distribute authorization in the first place.&lt;/p&gt;
&lt;p&gt;To answer that I looked in the spec. I searched for &amp;quot;signature&amp;quot; and found
nothing particularly relevant. Eventually I found the &lt;a href=&#34;https://www.w3.org/TR/activitypub/#authorization&#34;&gt;Authentication and
Authorization&lt;/a&gt; section, which says &amp;quot;Unfortunately at the time of
standardization, there are no strongly agreed upon mechanisms for
authentication.&amp;quot; Well, shit. Clearly &lt;em&gt;some people&lt;/em&gt; agree enough for it to be
implemented, but I guess not enough for it to be actually specified!&lt;/p&gt;
&lt;p&gt;This does, mercifully, link to &lt;a href=&#34;https://www.w3.org/wiki/ActivityPub/Primer/Authentication_Authorization&#34;&gt;a wiki page&lt;/a&gt; that purports to lay out &amp;quot;some
possible directions&amp;quot; and, under the &lt;a href=&#34;https://www.w3.org/wiki/ActivityPub/Primer/Authentication_Authorization#Server_to_Server&#34;&gt;Server to Server&lt;/a&gt; section, seems to
describe the scheme that &lt;a href=&#34;https://stackoverflow.com/questions/75025657/activitypub-mastodon-how-to-get-an-actor#answer-76396982&#34;&gt;this StackOverflow post&lt;/a&gt; describes as &amp;quot;an odd,
somewhat well-known ActivityPub quirk&amp;quot;&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;https://nex-3.com/blog/so-im-trying-to-add-support/#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. This wiki page may not be an official
specification, but at the very least it describes the &lt;code&gt;publicKey&lt;/code&gt; field that I
can see in the actor JSON on Mastodon.social.&lt;/p&gt;
&lt;p&gt;This is all fundamentally busywork. Because the whole thing is decentralized,
the receiving instance has no choice but to trust whatever public key a new
requesting instance provides. All this scheme really does is prove that
someone making requests runs a server somewhere that speaks basic ActivityPub,
and even then this constraint only exists for ActivityPub requests—HTTP
requires no authentication at all.&lt;/p&gt;
&lt;pre class=&#34;language-json&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;&lt;span class=&#34;token punctuation&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;id&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://mastodon.social/users/nex3&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;type&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;Person&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token comment&#34;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;publicKey&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;token property&#34;&gt;&#34;id&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://mastodon.social/users/nex3#main-key&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;token property&#34;&gt;&#34;owner&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://mastodon.social/users/nex3&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;token property&#34;&gt;&#34;publicKeyPem&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n&#34;&lt;/span&gt;
  &lt;span class=&#34;token punctuation&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or does it? The &lt;code&gt;publicKey&lt;/code&gt; link there points to
&lt;a href=&#34;https://web-payments.org/vocabs/security#publicKey&#34;&gt;https://web-payments.org/vocabs/security#publicKey&lt;/a&gt;, a URL that at time of
writing is refusing HTTPS connections entirely. Naturally I looked it up on
&lt;a href=&#34;http://archive.org&#34;&gt;archive.org&lt;/a&gt;, only to find that &lt;a href=&#34;https://web.archive.org/web/20221218063101/https://web-payments.org/vocabs/security#publicKey&#34;&gt;the specification for the &lt;code&gt;publicKey&lt;/code&gt; field&lt;/a&gt; is
not only totally different from what I&#39;m observing in the wild, its one-sentence
specification is essentially useless: &amp;quot;A public key property is used to specify
a URL that contains information about a public key.&amp;quot; The example included
&lt;em&gt;doesn&#39;t even have a &lt;code&gt;publicKey&lt;/code&gt; field&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&#34;language-json&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;&lt;span class=&#34;token punctuation&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;@context&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://w3id.org/security/v1&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;@id&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://payswarm.example.com/i/bob/keys/1&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;@type&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;Key&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;owner&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;https://payswarm.example.com/i/bob&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;token property&#34;&gt;&#34;publicKeyPem&#34;&lt;/span&gt;&lt;span class=&#34;token operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;-----BEGIN PRIVATE KEY-----\nMIIBG0BA...OClDQAB\n-----END PRIVATE KEY-----\n&#34;&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, so there&#39;s functionally no specification for the data format. That&#39;s fine,
I can probably reverse-engineer it from the live example in combination with the
spec for how to make authenticated requests. A spec which is &lt;a href=&#34;https://tools.ietf.org/html/draft-cavage-http-signatures-08&#34;&gt;handily linked&lt;/a&gt;
from that same wiki page. But nothing can be easy: that link has a prominent
sidebar which reads &amp;quot;This is an older version of an Internet-Draft whose latest
revision state is &#39;Replaced&#39;.&amp;quot;&lt;/p&gt;
&lt;p&gt;So is the ActivityPub authorization &amp;quot;specification&amp;quot; &lt;em&gt;intentionally&lt;/em&gt; using an
outdated version of HTTP signatures, or should I use the latest version instead?
The wiki page doesn&#39;t say, so I just have to guess. Presumably there are plenty
of implementations out there that use the version that was (I&#39;m assuming?)
current at the time the spec was written, so I&#39;ll start with that. It describes
how to link back to the actor&#39;s public key (although &lt;em&gt;not&lt;/em&gt; what format that key
should be in), which headers to sign, and how to create a signature given a
choice of algorithm.&lt;/p&gt;
&lt;p&gt;On the subject of algorithms, it says &amp;quot;Valid values for this parameter can be
found in the Signature Algorithms registry located at
&lt;a href=&#34;http://www.iana.org/assignments/signature-algorithms&#34;&gt;http://www.iana.org/assignments/signature-algorithms&lt;/a&gt; and MUST NOT be marked
&amp;quot;deprecated&amp;quot;.&amp;quot; An astute observer will note that that link is completely dead.
In fact, even the Internet Archive doesn&#39;t seem to have a real copy of it. As
far as I can tell, this spec is linking to a document that &lt;em&gt;never existed&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Okay, so much for the outdated HTTP signature specification. Fortunately, it was
eventually published as the real-ass &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc9421.html&#34;&gt;RFC 9421&lt;/a&gt; which makes reference to the
real name of the IANA registry, &lt;a href=&#34;https://www.iana.org/assignments/http-message-signature/http-message-signature.xhtml&#34;&gt;&amp;quot;HTTP Message Signature&amp;quot;&lt;/a&gt;, although
inexplicably does not include a link to it. Unfortunately, the RFC&#39;s structure
for HTTP signatures is totally incompatible with the older draft&#39;s, so it&#39;s
still entirely unclear which one Mastodon instances want.&lt;/p&gt;
&lt;p&gt;At this point, I have two major outstanding questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;What is the correct format for the public key with which I&#39;m supposed to sign
requests?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Should I use the outdated draft HTTP Signature format, or the one from RFC
9421?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, I don&#39;t think there&#39;s any way to answer these questions other
than to read through an existing implementation&#39;s code, which is a treat I&#39;ll
save myself for some other day.&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;For those who are curious, the authorization scheme is essentially as
follows: when one ActivityPub server makes an authorized request to another,
it includes a cryptographic signature of some of that request&#39;s headers using
an actor&#39;s private key. The actor may be the signed-in user, but when
requesting public data it can also be an &amp;quot;instance actor&amp;quot; representing the
instance as a whole. This request also includes the URL of the actor so the
receiving instance can fetch its public key and verify the signature. &lt;a href=&#34;https://nex-3.com/blog/so-im-trying-to-add-support/#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
    </entry>
  
    <entry>
      <title></title>
      <link href="https://nex-3.com/blog/doing-my-level-best-to/" rel="alternate"/>
      <id>https://nex-3.com/blog/doing-my-level-best-to/</id>
      <published>2024-10-03T01:24:58Z</published>
      <updated>2024-10-03T01:24:58Z</updated>
      <author><name>Natalie Weizenbaum</name>
          <uri>https://nex-3.com/</uri></author><category term="rss" label="rss"/><category term="mastodon" label="mastodon"/><content type="html">&lt;p&gt;doing my level best to replace my &amp;quot;click over to Cohost&amp;quot; instinct with &amp;quot;click
over to my RSS reader&amp;quot; instead of &amp;quot;click over to Mastodon&amp;quot;&lt;/p&gt;
</content>
    </entry>
  
</feed>

