annot.at#
This is a work in progress. Feel free to poke around and take it for a spin, but keep in mind it's very much under development.
A service for automatically publishing content to the Atmosphere, using the standard.site lexicon. Register your publication and a discovery mechanism, and your content is automatically published.
Requires your site to have a link rel=alternate for a feed set, and that you're able to verify your ownership by serving a /.well-known file.
Document rkeys are derived from the post <link rel="site.standard.document" href="<aturi>", so your blog must set that up. Document rkeys have to be TIDs to be valid, and should be stable, so either generate them and store them in your blog post fronmatter/metadata, or use a deterministic implementation that can run multiple times for the same post and give the same result.
TODO#
- Sign up/sign in with Bluesky
- Maybe some design?
- Add site including verification
- Write a guide for using this
- Document cover images
- Document content with html content type
- RSS poller
- standard.site document reader
- Post to Bluesky
- Let atproto drive things more
- List publications, including not explicitly added ones
- List documents, including not explicitly added ones
- List dangling documents/documents that no longer validate against post etc
Authenticating#
You can run the app locally and try out the full OAuth flow by exposing it to the internet using Tailscale or similar solutions. For example:
> tailscale funnel 4002
Available on the internet:
https://machine.random-thing.ts.net/
|-- proxy http://127.0.0.1:4002
Press Ctrl+C to exit.
Make sure that same host is set in dev.exs and the app has been restarted. Click login and use any active atproto handle, and you should be able to OAuth against it.
Deploying#
You need to set up some env vars to run this service in a production environment, SECRET_KEY_BASE, DATABASE_URL, HOST, CLOAK_KEY, and ATPROTO_CLIENT_PRIVATE_JWK.
SECRET_KEY_BASE- runmix phx.gen.secret 64and copy the outputDATABASE_URL- a Postgres database URL likepostgresql://app:pass@db:5432/db_nameHOST- a domain name likeannot.atCLOAK_KEY- runmix run -e 'IO.puts(Base.encode64(:crypto.strong_rand_bytes(32)))'and copy the outputATPROTO_CLIENT_PRIVATE_JWK- runmix run -e '{_, jwk} = JOSE.JWK.to_map(JOSE.JWK.generate_key({:ec, "P-256"})); IO.puts(Jason.encode!(jwk))'and copy the output
Note that ATPROTO_CLIENT_PRIVATE_JWK, CLOAK_KEY, and SECRET_KEY_BASE are secrets and should not be shared.