@@ -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"}})