@@ -35,6 +35,7 @@ sessionExpiry = 3600000 -- 1 hour in milliseconds
3535onlineGossipTtl = 3600 -- 1 hour in seconds
3636offlineGossipMinTtl = 60 -- minimum TTL for offline gossip events in seconds
3737maxForwardRetriesPerServer = 100
38+federationEnabled = not (federationSecret == "")
3839
3940-- ============================================
4041-- Types
@@ -42,7 +43,9 @@ maxForwardRetriesPerServer = 100
4243
4344type PollEvent = {id: Text, eventType: Text, payload: {encryptedBlob: Text, fromKey: Text, timestamp: Timestamp, toKey: Text}}
4445
45−type GossipEvent = {eventType: Text, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
46+type GossipEventType = Text where \s -> s == "online" || s == "offline"
47+
48+type GossipEvent = {eventType: GossipEventType, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
4649
4750type PubkeyHex = Text where \s -> isValidHex s && not (tooLong s maxPubkeyLen)
4851type BlobHex = Text where \s -> isValidHex s && not (tooLong s maxBlobLen)
@@ -124,6 +127,12 @@ route Api = AuthApi | ClientApi | FederationApi | MaintenanceApi
124127-- Helpers
125128-- ============================================
126129
130+any = \xs pred -> count (do x <- xs; where pred x; yield x) > 0
131+none = \xs pred -> count (do x <- xs; where pred x; yield x) == 0
132+isJust = \m -> case m of
133+ Nothing {} -> False {}
134+ _ -> True {}
135+
127136msToS : Int<Ms> -> Int<S>
128137msToS = \x -> x / 1000
129138
@@ -288,6 +297,25 @@ containsLocalhostSuffix = \s -> containsSuffix ".localhost" 10 s
288297containsLocalSuffix = \s -> containsSuffix ".local" 6 s
289298containsInternalSuffix = \s -> containsSuffix ".internal" 9 s
290299
300+is172Private = \sn ->
301+ take 4 sn == "172."
302+ && let d1 = take 1 (drop 4 sn) in
303+ let d2 = take 1 (drop 5 sn) in
304+ take 1 (drop 6 sn) == "."
305+ && ((d1 == "1" && (d2 == "6" || d2 == "7" || d2 == "8" || d2 == "9"))
306+ || (d1 == "2" && isDigitChar d2)
307+ || (d1 == "3" && (d2 == "0" || d2 == "1")))
308+
309+isHighOctetPrefix = \sn ->
310+ take 1 sn == "2"
311+ && let d2 = take 1 (drop 1 sn) in
312+ let d3 = take 1 (drop 2 sn) in
313+ take 1 (drop 3 sn) == "."
314+ && ((d2 == "2" && (d3 == "4" || d3 == "5" || d3 == "6" || d3 == "7" || d3 == "8" || d3 == "9"))
315+ || (d2 == "3" && isDigitChar d3)
316+ || (d2 == "4" && isDigitChar d3)
317+ || (d2 == "5" && (d3 == "0" || d3 == "1" || d3 == "2" || d3 == "3" || d3 == "4" || d3 == "5")))
318+
291319isBadServerName = \s ->
292320 let sn = toLower (stripTrailingDot s) in
293321 sn == ""
@@ -305,10 +333,7 @@ isBadServerName = \s ->
305333 || take 4 sn == "127." || take 3 sn == "10."
306334 || take 8 sn == "192.168." || take 8 sn == "169.254."
307335 || take 2 sn == "0." || take 1 sn == "["
308− || take 7 sn == "172.16." || take 7 sn == "172.17." || take 7 sn == "172.18." || take 7 sn == "172.19."
309− || take 7 sn == "172.20." || take 7 sn == "172.21." || take 7 sn == "172.22." || take 7 sn == "172.23."
310− || take 7 sn == "172.24." || take 7 sn == "172.25." || take 7 sn == "172.26." || take 7 sn == "172.27."
311− || take 7 sn == "172.28." || take 7 sn == "172.29." || take 7 sn == "172.30." || take 7 sn == "172.31."
336+ || is172Private sn
312337 || take 7 sn == "198.18." || take 7 sn == "198.19."
313338 || take 8 sn == "192.0.0."
314339 || take 8 sn == "192.0.2."
@@ -321,14 +346,7 @@ isBadServerName = \s ->
321346 || hasOctalOctet sn
322347 || hasHexPrefix sn
323348 || (isDigitChar (take 1 sn) && isAllDigitsOrDotsUntilColonOrEnd sn)
324− || take 4 sn == "224." || take 4 sn == "225." || take 4 sn == "226." || take 4 sn == "227."
325− || take 4 sn == "228." || take 4 sn == "229." || take 4 sn == "230." || take 4 sn == "231."
326− || take 4 sn == "232." || take 4 sn == "233." || take 4 sn == "234." || take 4 sn == "235."
327− || take 4 sn == "236." || take 4 sn == "237." || take 4 sn == "238." || take 4 sn == "239."
328− || take 4 sn == "240." || take 4 sn == "241." || take 4 sn == "242." || take 4 sn == "243."
329− || take 4 sn == "244." || take 4 sn == "245." || take 4 sn == "246." || take 4 sn == "247."
330− || take 4 sn == "248." || take 4 sn == "249." || take 4 sn == "250." || take 4 sn == "251."
331− || take 4 sn == "252." || take 4 sn == "253." || take 4 sn == "254." || take 4 sn == "255."
349+ || isHighOctetPrefix sn
332350
333351lookupSession = \sessions token t ->
334352 fold (\acc s ->
@@ -345,21 +363,17 @@ extractToken = \authHeader ->
345363 then drop 7 authHeader
346364 else ""
347365
348−verifyFederationAuth = \authorization ->
349− let token = extractToken authorization in
350− let result = safeCompare token (if federationSecret == "" then "x" else federationSecret) in
351− let secretSet = if federationSecret == "" then 0 else 1 in
366+verifySecret = \token secret ->
367+ let result = safeCompare token (if secret == "" then "x" else secret) in
368+ let secretSet = if secret == "" then 0 else 1 in
352369 (if result then 1 else 0) * secretSet > 0
353370
371+verifyFederationAuth = \authorization ->
372+ verifySecret (extractToken authorization) federationSecret
373+
354374verifyMaintenanceAuth = \authorization ->
355375 let token = extractToken authorization in
356− let fedResult = safeCompare token (if federationSecret == "" then "x" else federationSecret) in
357− let maintResult = safeCompare token (if maintenanceSecret == "" then "x" else maintenanceSecret) in
358− let fedN = if fedResult then 1 else 0 in
359− let maintN = if maintResult then 1 else 0 in
360− let fedSecretSet = if federationSecret == "" then 0 else 1 in
361− let maintSecretSet = if maintenanceSecret == "" then 0 else 1 in
362− fedN * fedSecretSet + maintN * maintSecretSet > 0
376+ verifySecret token federationSecret || verifySecret token maintenanceSecret
363377
364378clampTtl = \ttl -> if ttl < 1 then 1 else if ttl > maxPresenceTtl then maxPresenceTtl else ttl
365379
@@ -369,7 +383,7 @@ dedupMessageIds = \messageIds ->
369383 fold (\acc mid ->
370384 let nmid = normalizeHex mid in
371385 if count acc >= maxMessageIds then acc
372− else if count (do a <- acc; where a == nmid; yield a) > 0 then acc
386+ else if any acc (\a -> a == nmid) then acc
373387 else union acc [nmid]) [] messageIds
374388
375389boundedSmallest = \items n getKey ->
@@ -417,7 +431,7 @@ collectPeerServers = \items getServer ->
417431 fold (\acc item ->
418432 let s = getServer item in
419433 if s == serverHostN then acc
420− else if count (do a <- acc; where a == s; yield a) > 0 then acc
434+ else if any acc (\a -> a == s) then acc
421435 else union acc [s]) [] items
422436
423437validGossipEvents = \events validRequest t eventType ->
@@ -481,11 +495,7 @@ pruneExpired = \t -> do
481495 p <- presenceBefore
482496 where p.expiresAt <= t
483497 where p.server == serverHostN
484− where count (do
485− q <- presenceAfter
486− where q.pubkey == p.pubkey
487− where q.server == serverHostN
488− yield q) == 0
498+ where none presenceAfter (\q -> q.pubkey == p.pubkey && q.server == serverHostN)
489499 yield p), peerServers: peerServersBefore}
490500
491501maybePrune = \t -> do
@@ -522,11 +532,11 @@ sendBatchedGossip = \peerServers allEvents ->
522532
523533broadcastOfflineGossip = \t peerServers expiredLocal -> do
524534 let expiredEntries = fold (\acc p ->
525− if count (do a <- acc; where a.pubkey == p.pubkey; where a.expiresAt >= p.expiresAt; yield a) > 0 then acc
535+ if any acc (\a -> a.pubkey == p.pubkey && a.expiresAt >= p.expiresAt) then acc
526536 else union
527537 (do a <- acc; where not (a.pubkey == p.pubkey); yield a)
528538 [{pubkey: p.pubkey, ttl: (let rawTtl = (p.expiresAt - p.timestamp) / 1000 in clampTtl (if rawTtl < offlineGossipMinTtl then offlineGossipMinTtl else rawTtl)), expiresAt: p.expiresAt}]) [] expiredLocal
529− if not (federationSecret == "") && count expiredEntries > 0 && count peerServers > 0
539+ if federationEnabled && count expiredEntries > 0 && count peerServers > 0
530540 then do
531541 let gossipEvents = do
532542 e <- expiredEntries
@@ -586,7 +596,7 @@ sendBatchedAcksToServer = \serverAcks server ->
586596 ackedIds <- *ackedIds
587597 set *ackedIds = do
588598 a <- ackedIds
589− where not (a.originServer == server && count (do sa <- batch; where sa.messageId == a.messageId; where sa.toKey == a.toKey; yield sa) > 0)
599+ where not (a.originServer == server && any batch (\sa -> sa.messageId == a.messageId && sa.toKey == a.toKey))
590600 yield a
591601 Err _ -> yield {}
592602 sendBatchedAcksToServer rest server
@@ -612,10 +622,10 @@ pruneAndRetry = \t -> do
612622 yield a
613623 yield {expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, pendingForwards: pendingForwards, pendingAcks: pendingAcks}
614624 broadcastOfflineGossip t result.peerServers result.expiredLocal
615− if not (federationSecret == "") && count result.pendingForwards > 0
625+ if federationEnabled && count result.pendingForwards > 0
616626 then retryPendingForwards result.pendingForwards
617627 else yield {}
618− if not (federationSecret == "") && count result.pendingAcks > 0
628+ if federationEnabled && count result.pendingAcks > 0
619629 then do
620630 let ackOriginServers = collectPeerServers result.pendingAcks (\a -> a.originServer)
621631 sendAcksAndClean result.pendingAcks ackOriginServers
@@ -640,9 +650,7 @@ pollOnce = \token cursor -> do
640650 where m.receivedAt > clampedCursor
641651 yield m
642652 let limitedMsgs = boundedSmallest matchingMsgs maxPollEvents (\m -> m.receivedAt)
643− let authorized = case session of
644− Nothing {} -> False {}
645− _ -> True {}
653+ let authorized = isJust session
646654 let evts = do
647655 m <- limitedMsgs
648656 yield {id: m.messageId, eventType: "message",
@@ -750,12 +758,12 @@ serve = \req -> case req of
750758 then union presenceEvicted [{pubkey: pubkey, server: serverHostN, expiresAt: expiry, timestamp: t}]
751759 else presence
752760 set *presence = updatedPresence
753− let peerServers = if sigValid && not (federationSecret == "")
761+ let peerServers = if sigValid && federationEnabled
754762 then collectPeerServers updatedPresence (\p -> p.server)
755763 else []
756764 yield {sigValid: sigValid, peerServers: peerServers, expiredLocal: pr.expiredLocal, offlinePeers: pr.peerServers}
757765 fork (do
758− if result.sigValid && not (federationSecret == "")
766+ if result.sigValid && federationEnabled
759767 then sendToEach result.peerServers (\server -> do
760768 fetchResult <- fetch (federationScheme ++ server) (RecvGossip {
761769 authorization: "Bearer " ++ federationSecret,
@@ -800,9 +808,7 @@ serve = \req -> case req of
800808 let fromKey = case session of
801809 Nothing {} -> ""
802810 Just {value: s} -> s.pubkey
803− let authorized = case session of
804− Nothing {} -> False {}
805− _ -> True {}
811+ let authorized = isJust session
806812 seqCounter <- *seqCounter
807813 let seqTs = if t > seqCounter then t else seqCounter + 1
808814 let recipientMsgCount = count (do
@@ -817,12 +823,7 @@ serve = \req -> case req of
817823 [{messageId: msgId, toKey: to, fromKey: fromKey,
818824 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: "", receivedAt: seqTs}]
819825 else messages
820− let localOnline = authorized && count (do
821− p <- presence
822− where p.pubkey == to
823− where p.server == serverHostN
824− where p.expiresAt > t
825− yield p) > 0
826+ let localOnline = authorized && any presence (\p -> p.pubkey == to && p.server == serverHostN && p.expiresAt > t)
826827 let remoteServers = if authorized
827828 then do
828829 p <- presence
@@ -842,13 +843,13 @@ serve = \req -> case req of
842843 let forwardServers = fold (\acc s ->
843844 if count acc >= forwardSlots then acc
844845 else union acc [s]) [] remoteServers
845− set *forwards = if shouldInsert && not forwardsAtCapacity && count forwardServers > 0 && not (federationSecret == "")
846+ set *forwards = if shouldInsert && not forwardsAtCapacity && count forwardServers > 0 && federationEnabled
846847 then union forwards (do s <- forwardServers; yield {messageId: msgId, toServer: s, createdAt: t, toKey: to, fromKey: fromKey, encryptedBlob: encryptedBlob, timestamp: clampedTs})
847848 else forwards
848849 yield {status: status, remoteServers: remoteServers, fromKey: fromKey, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, forwardsAtCapacity: forwardsAtCapacity}
849− let finalStatus = if result.status == "federated" && (federationSecret == "" || result.forwardsAtCapacity) then "queued" else result.status
850+ let finalStatus = if result.status == "federated" && (not federationEnabled || result.forwardsAtCapacity) then "queued" else result.status
850851 fork (do
851− if count result.remoteServers > 0 && not (result.status == "unauthorized") && not (result.status == "rejected") && not (federationSecret == "")
852+ if count result.remoteServers > 0 && not (result.status == "unauthorized") && not (result.status == "rejected") && federationEnabled
852853 then sendToEach result.remoteServers (\server -> do
853854 fwdResult <- fetch (federationScheme ++ server) (ForwardMessage {
854855 toKey: to, fromKey: result.fromKey, encryptedBlob: encryptedBlob,
@@ -902,9 +903,7 @@ serve = \req -> case req of
902903 let evictedEntries = if excessCount <= 0 then []
903904 else diff combinedAckedIds afterEviction
904905 set *ackedIds = afterEviction
905− let ok = case session of
906− Nothing {} -> False {}
907− _ -> True {}
906+ let ok = isJust session
908907 yield {ok: ok, ackedMessages: ackedMessages, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, evictedEntries: evictedEntries}
909908 let fedMessages = do
910909 m <- result.ackedMessages
@@ -913,7 +912,7 @@ serve = \req -> case req of
913912 yield m
914913 let originServers = collectPeerServers fedMessages (\m -> m.originServer)
915914 fork (do
916− if result.ok && count originServers > 0 && not (federationSecret == "")
915+ if result.ok && count originServers > 0 && federationEnabled
917916 then do
918917 let pendingAcks = do
919918 m <- fedMessages
@@ -924,9 +923,9 @@ serve = \req -> case req of
924923 then do
925924 let evictedToRetry = do
926925 a <- result.evictedEntries
927− where count (do m <- fedMessages; where m.messageId == a.messageId; where m.toKey == a.toKey; yield m) == 0
926+ where none fedMessages (\m -> m.messageId == a.messageId && m.toKey == a.toKey)
928927 yield a
929− if count evictedToRetry > 0 && not (federationSecret == "")
928+ if count evictedToRetry > 0 && federationEnabled
930929 then do
931930 let evictedOriginServers = collectPeerServers evictedToRetry (\a -> a.originServer)
932931 sendToEach evictedOriginServers (\server -> do
@@ -963,9 +962,7 @@ serve = \req -> case req of
963962 sessions <- *sessions
964963 presence <- *presence
965964 let session = lookupSession sessions (extractToken authorization) t
966− let authorized = case session of
967− Nothing {} -> False {}
968− _ -> True {}
965+ let authorized = isJust session
969966 let valid = do
970967 p <- presence
971968 where p.pubkey == pubkey
@@ -976,7 +973,7 @@ serve = \req -> case req of
976973 Just {value: _} ->
977974 if count valid == 0
978975 then ""
979− else if count (do p <- valid; where p.server == serverHostN; yield p) > 0
976+ else if any valid (\p -> p.server == serverHostN)
980977 then serverHostN
981978 else (fold (\acc p -> if p.expiresAt > acc.best then {server: p.server, best: p.expiresAt} else acc) {server: "", best: 0} valid).server
982979 yield {foundServer: foundServer, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
@@ -993,13 +990,7 @@ serve = \req -> case req of
993990 let offlineEntries = validGossipEvents events validRequest t "offline"
994991 let filteredOnline = do
995992 e <- onlineEntries
996− where count (do
997− o <- offlineEntries
998− where o.server == fromServer
999− where o.pubkey == e.pubkey
1000− where o.server == e.server
1001− where o.timestamp > e.timestamp
1002− yield o) == 0
993+ where none offlineEntries (\o -> o.server == fromServer && o.pubkey == e.pubkey && o.server == e.server && o.timestamp > e.timestamp)
1003994 yield {pubkey: e.pubkey, server: e.server, expiresAt: e.expiresAt, timestamp: e.timestamp, ttl: e.ttl}
1004995 let affectedKeys = union
1005996 (do
@@ -1009,12 +1000,7 @@ serve = \req -> case req of
10091000 e <- offlineEntries
10101001 yield {pubkey: e.pubkey, server: e.server})
10111002 let deduped = fold (\acc e ->
1012− if count (do
1013− a <- acc
1014− where a.pubkey == e.pubkey
1015− where a.server == e.server
1016− where a.expiresAt >= e.expiresAt
1017− yield a) > 0
1003+ if any acc (\a -> a.pubkey == e.pubkey && a.server == e.server && a.expiresAt >= e.expiresAt)
10181004 then acc
10191005 else union
10201006 (do
@@ -1027,7 +1013,7 @@ serve = \req -> case req of
10271013 presence <- *presence
10281014 let trustedDeduped = do
10291015 e <- deduped
1030− where e.server == fromServer || count (do p <- presence; where p.server == e.server; where p.expiresAt > t; yield p) > 0
1016+ where e.server == fromServer || any presence (\p -> p.server == e.server && p.expiresAt > t)
10311017 yield e
10321018 let trustedOffline = do
10331019 e <- offlineEntries
@@ -1035,20 +1021,10 @@ serve = \req -> case req of
10351021 yield e
10361022 let appliedOnline = do
10371023 e <- trustedDeduped
1038− where count (do
1039− p <- presence
1040− where p.pubkey == e.pubkey
1041− where p.server == e.server
1042− where p.expiresAt >= e.expiresAt
1043− yield p) == 0
1024+ where none presence (\p -> p.pubkey == e.pubkey && p.server == e.server && p.expiresAt >= e.expiresAt)
10441025 yield {pubkey: e.pubkey, server: e.server}
10451026 let merged = fold (\acc e ->
1046− if count (do
1047− p <- acc
1048− where p.pubkey == e.pubkey
1049− where p.server == e.server
1050− where p.expiresAt >= e.expiresAt
1051− yield p) > 0
1027+ if any acc (\p -> p.pubkey == e.pubkey && p.server == e.server && p.expiresAt >= e.expiresAt)
10521028 then acc
10531029 else union
10541030 (do
@@ -1058,45 +1034,25 @@ serve = \req -> case req of
10581034 [e]) presence trustedDeduped
10591035 let offlineOnlyKeys = do
10601036 k <- affectedKeys
1061− where count (do d <- trustedDeduped; where d.pubkey == k.pubkey; where d.server == k.server; yield d) == 0
1037+ where none trustedDeduped (\d -> d.pubkey == k.pubkey && d.server == k.server)
10621038 yield k
10631039 let appliedOffline = do
10641040 k <- offlineOnlyKeys
1065− where count (do
1066− p <- presence
1067− where p.pubkey == k.pubkey
1068− where p.server == k.server
1069− where count (do
1070− o <- trustedOffline
1071− where o.pubkey == k.pubkey
1072− where o.server == k.server
1073− where (if o.timestamp > t then t else o.timestamp) > p.timestamp
1074− yield o) > 0
1075− yield p) > 0
1041+ where any presence (\p -> p.pubkey == k.pubkey && p.server == k.server && any trustedOffline (\o -> o.pubkey == k.pubkey && o.server == k.server && (if o.timestamp > t then t else o.timestamp) > p.timestamp))
10761042 yield {pubkey: k.pubkey, server: k.server}
10771043 let afterOffline = diff merged (do
10781044 p <- merged
10791045 k <- offlineOnlyKeys
10801046 where p.pubkey == k.pubkey
10811047 where p.server == k.server
1082− where count (do
1083− o <- trustedOffline
1084− where o.pubkey == k.pubkey
1085− where o.server == k.server
1086− where (if o.timestamp > t then t else o.timestamp) > p.timestamp
1087− yield o) > 0
1048+ where any trustedOffline (\o -> o.pubkey == k.pubkey && o.server == k.server && (if o.timestamp > t then t else o.timestamp) > p.timestamp)
10881049 yield p)
10891050 let withinCapacity = count afterOffline <= maxPresenceEntries
10901051 let updatesOnlyMerged = if withinCapacity then afterOffline
10911052 else fold (\acc e ->
1092− if count (do
1093− p <- acc
1094− where p.pubkey == e.pubkey
1095− where p.server == e.server
1096− where p.expiresAt >= e.expiresAt
1097− yield p) > 0
1053+ if any acc (\p -> p.pubkey == e.pubkey && p.server == e.server && p.expiresAt >= e.expiresAt)
10981054 then acc
1099− else if count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
1055+ else if any presence (\p -> p.pubkey == e.pubkey && p.server == e.server)
11001056 then union
11011057 (do
11021058 p <- acc
@@ -1110,19 +1066,14 @@ serve = \req -> case req of
11101066 k <- offlineOnlyKeys
11111067 where p.pubkey == k.pubkey
11121068 where p.server == k.server
1113− where count (do
1114− o <- trustedOffline
1115− where o.pubkey == k.pubkey
1116− where o.server == k.server
1117− where (if o.timestamp > t then t else o.timestamp) > p.timestamp
1118− yield o) > 0
1069+ where any trustedOffline (\o -> o.pubkey == k.pubkey && o.server == k.server && (if o.timestamp > t then t else o.timestamp) > p.timestamp)
11191070 yield p)
11201071 let reclaimCapacity = if withinCapacity then 0 else maxPresenceEntries - count updatesOnlyAfterOffline
11211072 let newEntries = if withinCapacity then []
11221073 else do
11231074 e <- trustedDeduped
1124− where count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) == 0
1125− where count (do p <- updatesOnlyAfterOffline; where p.pubkey == e.pubkey; where p.server == e.server; yield p) == 0
1075+ where none presence (\p -> p.pubkey == e.pubkey && p.server == e.server)
1076+ where none updatesOnlyAfterOffline (\p -> p.pubkey == e.pubkey && p.server == e.server)
11261077 yield e
11271078 let reclaimedEntries = if withinCapacity then []
11281079 else fold (\acc e ->
@@ -1134,13 +1085,8 @@ serve = \req -> case req of
11341085 else union
11351086 (do
11361087 e <- trustedDeduped
1137− where count (do p <- presence; where p.pubkey == e.pubkey; where p.server == e.server; yield p) > 0
1138− where count (do
1139− p <- presence
1140− where p.pubkey == e.pubkey
1141− where p.server == e.server
1142− where p.expiresAt >= e.expiresAt
1143− yield p) == 0
1088+ where any presence (\p -> p.pubkey == e.pubkey && p.server == e.server)
1089+ where none presence (\p -> p.pubkey == e.pubkey && p.server == e.server && p.expiresAt >= e.expiresAt)
11441090 yield {pubkey: e.pubkey, server: e.server})
11451091 (do
11461092 e <- reclaimedEntries
@@ -1153,24 +1099,19 @@ serve = \req -> case req of
11531099 yield {appliedKeys: (if withinCapacity then union appliedOnline appliedOffline else union appliedOnlineUpdates appliedOffline), expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, gossipPeerServers: gossipPeerServers, withinCapacity: withinCapacity}
11541100 let filteredOffline = do
11551101 e <- offlineEntries
1156− where count (do
1157− o <- onlineEntries
1158− where o.pubkey == e.pubkey
1159− where o.server == e.server
1160− where o.timestamp > e.timestamp
1161− yield o) == 0
1102+ where none onlineEntries (\o -> o.pubkey == e.pubkey && o.server == e.server && o.timestamp > e.timestamp)
11621103 yield e
11631104 let effectiveEvents = do
11641105 e <- union
11651106 (do e <- filteredOnline; yield {eventType: "online", pubkey: e.pubkey, server: e.server, timestamp: e.timestamp, ttl: e.ttl})
11661107 (do e <- filteredOffline; yield {eventType: "offline", pubkey: e.pubkey, server: e.server, timestamp: e.timestamp, ttl: e.ttl})
1167− where count (do a <- gossipResult.appliedKeys; where a.pubkey == e.pubkey; where a.server == e.server; yield a) > 0
1108+ where any gossipResult.appliedKeys (\a -> a.pubkey == e.pubkey && a.server == e.server)
11681109 yield e
11691110 if not gossipResult.withinCapacity
11701111 then println ("gossip: presence at capacity (" ++ show maxPresenceEntries ++ "), limiting new entries from " ++ fromServer)
11711112 else yield {}
11721113 fork (do
1173− if validRequest && cappedHops > 1 && not (federationSecret == "") && count effectiveEvents > 0
1114+ if validRequest && cappedHops > 1 && federationEnabled && count effectiveEvents > 0
11741115 then do
11751116 let targets = do
11761117 s <- gossipResult.gossipPeerServers
@@ -1210,18 +1151,10 @@ serve = \req -> case req of
12101151 where m.receivedAt >= t - messageMaxAge
12111152 yield m)
12121153 let existsInMessages = if not (authorized && validOrigin) then False {}
1213− else count (do
1214− m <- messages
1215− where m.messageId == messageId
1216− where m.toKey == toKey
1217− yield m) > 0
1154+ else any messages (\m -> m.messageId == messageId && m.toKey == toKey)
12181155 ackedIds <- *ackedIds
12191156 let existsInAcked = if not (authorized && validOrigin) then False {}
1220− else count (do
1221− a <- ackedIds
1222− where a.messageId == messageId
1223− where a.toKey == toKey
1224− yield a) > 0
1157+ else any ackedIds (\a -> a.messageId == messageId && a.toKey == toKey)
12251158 let exists = existsInMessages || existsInAcked
12261159 let shouldInsert = authorized && validOrigin && not exists && recipientMsgCount < maxMessagesPerRecipient
12271160 set *seqCounter = if shouldInsert then seqTs else seqCounter