@@ -18,6 +18,7 @@ maxMessageIds = 100
18maxGossipEvents = 100
18maxGossipEvents = 100
19maxPollEvents = 50
19maxPollEvents = 50
20maxPresenceEntries = 10000
20maxPresenceEntries = 10000
21+maxMessagesPerRecipient = 500
21clockSkewTolerance = 5000 -- 5 seconds tolerance for clock skew between federated servers
22clockSkewTolerance = 5000 -- 5 seconds tolerance for clock skew between federated servers
23-- ============================================
24-- ============================================
@@ -138,8 +139,8 @@ verifyFederationAuth = \authorization ->
138clampTtl = \ttl -> if ttl < 1 then 1 else if ttl > maxPresenceTtl then maxPresenceTtl else ttl
139clampTtl = \ttl -> if ttl < 1 then 1 else if ttl > maxPresenceTtl then maxPresenceTtl else ttl
140safeCompareLoop = \s1 s2 result ->
141safeCompareLoop = \s1 s2 result ->
141− if s1 == "" && s2 == ""
142+ if s2 == ""
142− then result
143+ then result + (if s1 == "" then 0 else 1)
143 else safeCompareLoop (drop 1 s1) (drop 1 s2) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
144 else safeCompareLoop (drop 1 s1) (drop 1 s2) (result + (if take 1 s1 == take 1 s2 then 0 else 1))
145safeCompare = \a b -> safeCompareLoop a b 0 == 0
146safeCompare = \a b -> safeCompareLoop a b 0 == 0
@@ -155,9 +156,7 @@ sendToEach = \servers action ->
156 catch (action server) (\err -> do
157 catch (action server) (\err -> do
157 println ("federation: error reaching " ++ server ++ ": " ++ show err)
158 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 {})
161 sendToEach rest action
160 sendToEach rest action
163pruneExpired = \t -> do
162pruneExpired = \t -> do
@@ -381,13 +380,18 @@ serve = \req -> case req of
381 let session = lookupSession sessions (extractToken authorization) t
380 let session = lookupSession sessions (extractToken authorization) t
382 seqCounter <- *seqCounter
381 seqCounter <- *seqCounter
383 let seqTs = if t > seqCounter then t else seqCounter + 1
382 let seqTs = if t > seqCounter then t else seqCounter + 1
383+ let recipientMsgCount = count (do
386+ where m.receivedAt >= t - messageMaxAge
384 let shouldInsert = case session of
388 let shouldInsert = case session of
385 Nothing {} -> False {}
389 Nothing {} -> False {}
386− Just {value: _} -> validInput
390+ Just {value: _} -> validInput && recipientMsgCount < maxMessagesPerRecipient
387 set *seqCounter = if shouldInsert then seqTs else seqCounter
391 set *seqCounter = if shouldInsert then seqTs else seqCounter
388 set *messages = case session of
392 set *messages = case session of
389 Nothing {} -> messages
393 Nothing {} -> messages
390− Just {value: s} -> if validInput
394+ Just {value: s} -> if validInput && recipientMsgCount < maxMessagesPerRecipient
391 then union messages
395 then union messages
392 [{messageId: msgId, toKey: to, fromKey: s.pubkey,
396 [{messageId: msgId, toKey: to, fromKey: s.pubkey,
393 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: "", receivedAt: seqTs}]
397 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: "", receivedAt: seqTs}]
@@ -514,7 +518,7 @@ serve = \req -> case req of
515 let authorized = verifyFederationAuth authorization
519 let authorized = verifyFederationAuth authorization
516 let cappedHops = if hopsRemaining > 5 then 5 else hopsRemaining
520 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
518 let onlineEntries = do
522 let onlineEntries = do
519 e <- events
523 e <- events
520 where validRequest
524 where validRequest
@@ -580,6 +584,10 @@ serve = \req -> case req of
580 e <- deduped
584 e <- deduped
581 where e.server == fromServer || count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
585 where e.server == fromServer || count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
587+ let trustedOffline = do
589+ where e.server == fromServer || count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
583 let appliedOnline = do
591 let appliedOnline = do
584 e <- trustedDeduped
592 e <- trustedDeduped
585 where count (do
593 where count (do
@@ -614,7 +622,7 @@ serve = \req -> case req of
614 where p.pubkey == k.pubkey
622 where p.pubkey == k.pubkey
615 where p.server == k.server
623 where p.server == k.server
616 where count (do
624 where count (do
617− o <- offlineEntries
625+ o <- trustedOffline
618 where o.pubkey == k.pubkey
626 where o.pubkey == k.pubkey
619 where o.server == k.server
627 where o.server == k.server
620 where o.timestamp >= p.timestamp
628 where o.timestamp >= p.timestamp
@@ -627,7 +635,7 @@ serve = \req -> case req of
627 where p.pubkey == k.pubkey
635 where p.pubkey == k.pubkey
628 where p.server == k.server
636 where p.server == k.server
629 where count (do
637 where count (do
630− o <- offlineEntries
638+ o <- trustedOffline
631 where o.pubkey == k.pubkey
639 where o.pubkey == k.pubkey
632 where o.server == k.server
640 where o.server == k.server
633 where o.timestamp >= p.timestamp
641 where o.timestamp >= p.timestamp
@@ -658,7 +666,7 @@ serve = \req -> case req of
658 where p.pubkey == k.pubkey
666 where p.pubkey == k.pubkey
659 where p.server == k.server
667 where p.server == k.server
660 where count (do
668 where count (do
661− o <- offlineEntries
669+ o <- trustedOffline
662 where o.pubkey == k.pubkey
670 where o.pubkey == k.pubkey
663 where o.server == k.server
671 where o.server == k.server
664 where o.timestamp >= p.timestamp
672 where o.timestamp >= p.timestamp
@@ -739,13 +747,18 @@ serve = \req -> case req of
739 messages <- *messages
747 messages <- *messages
740 seqCounter <- *seqCounter
748 seqCounter <- *seqCounter
741 let seqTs = if t > seqCounter then t else seqCounter + 1
749 let seqTs = if t > seqCounter then t else seqCounter + 1
750+ let recipientMsgCount = count (do
752+ where m.toKey == toKey
753+ where m.receivedAt >= t - messageMaxAge
742 let exists = count (do
755 let exists = count (do
743 m <- messages
756 m <- messages
744 where m.messageId == messageId
757 where m.messageId == messageId
745 where m.toKey == toKey
758 where m.toKey == toKey
746 where m.receivedAt >= t - messageMaxAge
759 where m.receivedAt >= t - messageMaxAge
747 yield m) > 0
760 yield m) > 0
748− let shouldInsert = authorized && validOrigin && validFields && not exists
761+ let shouldInsert = authorized && validOrigin && validFields && not exists && recipientMsgCount < maxMessagesPerRecipient
749 set *seqCounter = if shouldInsert then seqTs else seqCounter
762 set *seqCounter = if shouldInsert then seqTs else seqCounter
750 set *messages = if shouldInsert
763 set *messages = if shouldInsert
751 then union messages
764 then union messages