@@ -18,6 +18,7 @@ maxMessageIds = 100
1818maxGossipEvents = 100
1919maxPollEvents = 50
2020maxPresenceEntries = 10000
21+maxMessagesPerRecipient = 500
2122clockSkewTolerance = 5000 -- 5 seconds tolerance for clock skew between federated servers
2223
2324-- ============================================
@@ -138,8 +139,8 @@ verifyFederationAuth = \authorization ->
138139clampTtl = \ttl -> if ttl < 1 then 1 else if ttl > maxPresenceTtl then maxPresenceTtl else ttl
139140
140141safeCompareLoop = \s1 s2 result ->
141− if s1 == "" && s2 == ""
142− then result
142+ if s2 == ""
143+ then result + (if s1 == "" then 0 else 1)
143144 else safeCompareLoop (drop 1 s1) (drop 1 s2) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
144145
145146safeCompare = \a b -> safeCompareLoop a b 0 == 0
@@ -155,9 +156,7 @@ sendToEach = \servers action ->
155156 else do
156157 catch (action server) (\err -> do
157158 println ("federation: error reaching " ++ server ++ ": " ++ show err)
158− catch (action server) (\err2 -> do
159− println ("federation: retry failed for " ++ server ++ ": " ++ show err2)
160− yield {}))
159+ yield {})
161160 sendToEach rest action
162161
163162pruneExpired = \t -> do
@@ -381,13 +380,18 @@ serve = \req -> case req of
381380 let session = lookupSession sessions (extractToken authorization) t
382381 seqCounter <- *seqCounter
383382 let seqTs = if t > seqCounter then t else seqCounter + 1
383+ let recipientMsgCount = count (do
384+ m <- messages
385+ where m.toKey == to
386+ where m.receivedAt >= t - messageMaxAge
387+ yield m)
384388 let shouldInsert = case session of
385389 Nothing {} -> False {}
386− Just {value: _} -> validInput
390+ Just {value: _} -> validInput && recipientMsgCount < maxMessagesPerRecipient
387391 set *seqCounter = if shouldInsert then seqTs else seqCounter
388392 set *messages = case session of
389393 Nothing {} -> messages
390− Just {value: s} -> if validInput
394+ Just {value: s} -> if validInput && recipientMsgCount < maxMessagesPerRecipient
391395 then union messages
392396 [{messageId: msgId, toKey: to, fromKey: s.pubkey,
393397 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: "", receivedAt: seqTs}]
@@ -514,7 +518,7 @@ serve = \req -> case req of
514518 t <- now
515519 let authorized = verifyFederationAuth authorization
516520 let cappedHops = if hopsRemaining > 5 then 5 else hopsRemaining
517− let validRequest = authorized && cappedHops >= 0 && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen) && not (containsBadUrlChar fromServer) && count events <= maxGossipEvents
521+ let validRequest = authorized && cappedHops >= 1 && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen) && not (containsBadUrlChar fromServer) && count events <= maxGossipEvents
518522 let onlineEntries = do
519523 e <- events
520524 where validRequest
@@ -580,6 +584,10 @@ serve = \req -> case req of
580584 e <- deduped
581585 where e.server == fromServer || count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
582586 yield e
587+ let trustedOffline = do
588+ e <- offlineEntries
589+ where e.server == fromServer || count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
590+ yield e
583591 let appliedOnline = do
584592 e <- trustedDeduped
585593 where count (do
@@ -614,7 +622,7 @@ serve = \req -> case req of
614622 where p.pubkey == k.pubkey
615623 where p.server == k.server
616624 where count (do
617− o <- offlineEntries
625+ o <- trustedOffline
618626 where o.pubkey == k.pubkey
619627 where o.server == k.server
620628 where o.timestamp >= p.timestamp
@@ -627,7 +635,7 @@ serve = \req -> case req of
627635 where p.pubkey == k.pubkey
628636 where p.server == k.server
629637 where count (do
630− o <- offlineEntries
638+ o <- trustedOffline
631639 where o.pubkey == k.pubkey
632640 where o.server == k.server
633641 where o.timestamp >= p.timestamp
@@ -658,7 +666,7 @@ serve = \req -> case req of
658666 where p.pubkey == k.pubkey
659667 where p.server == k.server
660668 where count (do
661− o <- offlineEntries
669+ o <- trustedOffline
662670 where o.pubkey == k.pubkey
663671 where o.server == k.server
664672 where o.timestamp >= p.timestamp
@@ -739,13 +747,18 @@ serve = \req -> case req of
739747 messages <- *messages
740748 seqCounter <- *seqCounter
741749 let seqTs = if t > seqCounter then t else seqCounter + 1
750+ let recipientMsgCount = count (do
751+ m <- messages
752+ where m.toKey == toKey
753+ where m.receivedAt >= t - messageMaxAge
754+ yield m)
742755 let exists = count (do
743756 m <- messages
744757 where m.messageId == messageId
745758 where m.toKey == toKey
746759 where m.receivedAt >= t - messageMaxAge
747760 yield m) > 0
748− let shouldInsert = authorized && validOrigin && validFields && not exists
761+ let shouldInsert = authorized && validOrigin && validFields && not exists && recipientMsgCount < maxMessagesPerRecipient
749762 set *seqCounter = if shouldInsert then seqTs else seqCounter
750763 set *messages = if shouldInsert
751764 then union messages