Communities: - a post addressed to a community (to, cc or audience) is accepted according to its posting policy - followers, anyone, or moderators - and GroupDistributor announces the whole activity with `audience` to the community's followers, plus the object for new posts so Mastodon shows them; updates and deletes of community content are announced too; - top-level posts are Pages with a name (the title, or a headline from the text); /flock counts members, /wardens lists moderators; - a Mastodon client posts into a community by mentioning it, or into a remote group, which sets `audience`; - an Announce of an activity from a remote group a persona follows (Lemmy) is followed through: the object is fetched from its own origin, kept with its AudienceURI, and fanned out to the group's local followers; updates are applied in place and deletes checked against the origin. Circles stop being local-only: an undiscoverable Group actor whose follows are all requests the owner approves; posts addressed to the circle and its /flock and delivered to members' own inboxes, never announced, never public; a remote member's post into the circle is accepted from members only. SignedFetchAuthorizer serves circle posts and collections only to a signed request from a member or a member server's instance actor - 404 for anyone else. Circles never surface in search, lookups, mentions, account ids or profile pages. Federation:SecureMode requires a valid signature on every GET under /peasants except the instance actor. Group forms take a posting policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
7.1 KiB
Federation
PrivaPub is an ActivityPub server written in C#. This document follows FEP-67ff and describes how it federates.
Supported federation protocols and standards
- ActivityPub (server-to-server)
- WebFinger
- HTTP Signatures,
rsa-sha256/hs2019with RSA keys - NodeInfo 2.0 and 2.1
Supported FEPs
- FEP-67ff: FEDERATION.md
- FEP-f1d5: NodeInfo in Fediverse Software
- FEP-2c59: Discovery of a WebFinger address from an ActivityPub actor
Planned: FEP-1b12 (communities), FEP-8fcf (followers synchronisation), FEP-5feb (indexable), FEP-7628 (Move),
FEP-044f (quotes).
Actors
Every account is an avatar: one private login can own several, and they are deliberately unlinkable. Nothing in an actor document, a collection, NodeInfo or a delivery relates two avatars of the same login.
| Thing | Address |
|---|---|
| Actor (Person, Group, Application) | /peasants/{name} (/users/{name} redirects) |
| Inbox | /peasants/{name}/mouth |
| Outbox | /peasants/{name}/anus |
| Shared inbox | /human-centipede |
| Followers / following | /peasants/{name}/groupies, /peasants/{name}/stalking |
| Objects | /peasants/{name}/scribbles/{id} |
| Activities | /peasants/{name}/grunts/{id} |
| Direct-message context | /peasants/{name}/whispers/{id} |
| Profile and post pages | /@{name}, /@{name}/{id} |
The names are the project's own and are stable; resolve actors through WebFinger, not by guessing a path.
- The key is
{actor}#main-key, RSA 2048, served as SPKI PEM withownerset to the actor. publishedon an actor is truncated to the day.indexableisfalse.- The instance actor is
/peasants/privapub(typeApplication). It signs every fetch PrivaPub makes, so no avatar's key is used to read another server's content.
Groups
A group is either a community or a circle.
- A community follows FEP-1b12. Posts
addressed to it (in
to,ccoraudience) are accepted according to its posting policy (followers, anyone, or moderators only) and the groupAnnounces the whole activity, withaudienceset, to its followers. A new post is also announced as an object so Mastodon shows it. Updates and deletes of community content are announced too. A top-level post is aPagewith aname. Members are counted at/flock; moderators are listed at/wardens, whichattributedTodoes not yet point to. A mention of a community posts into it. - A circle is private. Its actor is not discoverable and every follow is a request. Its posts are addressed to the circle and its members collection, delivered to each member's own inbox and never announced. They are served only to a signed request from a member, or from the instance actor of a member's server; anyone else gets 404. A Mastodon member's replies reach only the people they mention.
- Announces from remote groups (Lemmy communities) are followed through to the activity: the object is fetched from its own origin, never taken from the announce.
Activities
Received:
| Activity | Effect |
|---|---|
Follow |
follows an avatar or community; Accept is sent unless the community approves members by hand |
Accept{Follow}, Reject{Follow} |
completes or ends a follow an avatar requested |
Undo{Follow, Like, Announce} |
reverses it |
Create{Note, Article, Page, Question, …} |
stored when a local avatar follows the author, is addressed or mentioned, when it replies to a local post, or when it is addressed to a community the author follows; a public parent is fetched to complete the thread |
Update{Note} |
replaces the content; the previous version is kept |
Update{Person} |
refetches the actor |
Like |
counted and notified, on posts the liker could see |
Announce |
counted and notified for local posts; shown to followers of the announcer, with the original refetched from its origin |
Delete |
deletes the object, or the actor and its follows |
Flag |
becomes a report for this server's moderators |
Sent: Follow, Undo{Follow}, Create{Note}, Update{Note}, Update{Person}, Delete{Tombstone}, Accept{Follow},
Reject{Follow}, Like, Announce and their Undo, Flag. A deleted post answers 410 with a Tombstone.
- Attachments are
Documents withmediaType,name(alt text),blurhash,focalPoint,widthandheight. Uploaded files have all metadata removed. - Pinned posts are the actor's
featuredcollection (/trophies);featuredTagsis/tattoos. - Blocks are never sent. A blocked account is sent
Reject{Follow}if it followed, and is unfollowed. - Reports are sent as
Flagby the instance actor, never by the reporting account.
A Create's Note carries Mastodon's content, contentMap, summary and sensitive, plus Mention and Hashtag
tags. A post's title becomes name and is also the first, bold line of content, because Mastodon does not show
name. A content warning without its own text uses the title, or "Content warning".
Visibility is expressed in to/cc the way Mastodon does it: public, unlisted, followers-only and direct. Inbound
followers-only posts are recognised by the author's own followers collection.
Local-only posts
Posts with a location (shown to nearby users of this server) never leave the server, in any form.
Security rules a peer will notice
- Signatures. Inbox POSTs must be signed over
(request-target),host,digestanddate(or(created)). The date may be at most one hour old and fifteen minutes ahead. A bad signature gets 401, malformed input 400, an accepted activity 202, too many requests 429. Activities are processed after the 202. - Origins. An actor document is accepted only from the address it names as its
id. A key only if its actor lists it withownerset to the actor and on the actor's origin. An activity'sid, and any object it creates, updates or deletes, must be on its actor's origin. An embedded object from another origin is fetched from that origin. - Fetching. All fetches are signed by the instance actor. They go only to public addresses, follow at most three redirects and read at most 1 MB.
- HTML. Received HTML is sanitised to Mastodon's allowlist.
- Delivery. Failed deliveries are retried with Mastodon's backoff (16 attempts). A host that keeps failing is paused, starting at an hour and growing to a week.
Known limitations
- Polls and custom emoji are not implemented.
- Remote media is fetched through this server's proxy when a local client displays it.
- Collections expose counts, not members.
- Only
rsa-sha256-style keys are verified. RFC 9421 signatures are planned.