on master help sign in
Fix bug #11: refuse inbound federation requests when federationEnabled is off

Outbound paths already guard on federationEnabled, but /federation/gossip and /federation/forward accepted peer writes to *presence/*messages even in single-node mode. Both now return 403 federation_disabled.

commita426743df4d9badfc11a62f4aaa7e593b1dd63a6 authoriko <mail@iko.soy> dateThu 11 Jun 2026, 13:52 (4 months ago) parent8ab1465
1 file changed+9−3
server.knot+9−3
server.knot+9−3
@@ -815,7 +815,9 @@ forkForwardsTo = \to encryptedBlob servers -> forEach servers (\server -> do
815815-- ============================================
816816-- Inbound peer-to-peer endpoints. Federation is open and unauthenticated:
817817-- the `no_presence` check in `handleForwardMessage` bounds forwards to
818−-- currently-online local keys.
818+-- currently-online local keys. Both handlers refuse with 403 when
819+-- `federationEnabled` is off, matching the outbound paths — a single-node
820+-- deployment accepts no peer writes to `*presence`/`*messages`.
819821
820822-- POST /federation/gossip: ingest peer presence events. The transport-level
821823-- `fromServer` is the home server for every event. Drops every (pubkey,
@@ -826,7 +828,9 @@ forkForwardsTo = \to encryptedBlob servers -> forEach servers (\server -> do
826828handleRecvGossip : [GossipEventType] -> Text -> IO {r *messages, rw *forwards, rw *presence, clock} (Result HttpError {})
827829handleRecvGossip = \events fromServer -> do
828830 t <- now
829− if isLocalServer fromServer || isBadServerName fromServer || count events > maxGossipEvents
831+ if not federationEnabled
832+ then yield (Err {error: {status: 403, message: "federation_disabled"}})
833+ else if isLocalServer fromServer || isBadServerName fromServer || count events > maxGossipEvents
830834 then yield (Err {error: {status: 400, message: "invalid_request"}})
831835 else do
832836 newlyOnline <- atomic (do
@@ -856,7 +860,9 @@ handleRecvGossip = \events fromServer -> do
856860handleForwardMessage : PubkeyHex -> BlobHex -> IO {rw *messages, r *presence, rw *seqCounter, clock} (Result HttpError {})
857861handleForwardMessage = \toKey encryptedBlob -> do
858862 t <- now
859− atomic (do
863+ if not federationEnabled
864+ then yield (Err {error: {status: 403, message: "federation_disabled"}})
865+ else atomic (do
860866 pres <- *presence
861867 if not hasLocalPresence pres toKey t
862868 then yield (Err {error: {status: 404, message: "no_presence"}})