@@ -49,6 +49,8 @@ type GossipEventType = Text where \s -> s == "online" || s == "offline"
50type GossipEvent = {eventType: GossipEventType, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
50type GossipEvent = {eventType: GossipEventType, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
52+type ValidGossipEntry = {pubkey: PubkeyHex, server: Text, expiresAt: Timestamp, timestamp: Timestamp, ttl: Int<S>}
52type MessageStatus = Text where \s -> s == "unauthorized" || s == "rejected" || s == "delivered" || s == "federated" || s == "queued"
54type MessageStatus = Text where \s -> s == "unauthorized" || s == "rejected" || s == "delivered" || s == "federated" || s == "queued"
54type PubkeyHex = Text where \s -> isValidHex s && not (tooLong s maxPubkeyLen)
56type PubkeyHex = Text where \s -> isValidHex s && not (tooLong s maxPubkeyLen)
@@ -68,7 +70,7 @@ type ForwardEntry = {messageId: MessageIdHex, toServer: ServerName, createdAt: T
68type AckedEntry = {messageId: MessageIdHex, toKey: PubkeyHex, ackedAt: Timestamp, originServer: ServerName}
70type AckedEntry = {messageId: MessageIdHex, toKey: PubkeyHex, ackedAt: Timestamp, originServer: ServerName}
69type AuthResult = {authorized: Bool, pubkey: Text}
71type AuthResult = {authorized: Bool, pubkey: Text}
70type PruneResult = {expiredLocal: [PresenceEntry], peerServers: [Text]}
72type PruneResult = {expiredLocal: [PresenceEntry], peerServers: [Text]}
71−type ForwardInfo = {messageId: MessageIdHex, toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp, toServer: ServerName}
73+
73-- ============================================
75-- ============================================
74-- Persisted State
76-- Persisted State
@@ -326,20 +328,23 @@ isHighOctetPrefix = \sn ->
326 || (d2 == "4" && isDigitChar d3)
328 || (d2 == "4" && isDigitChar d3)
327 || (d2 == "5" && (d3 == "0" || d3 == "1" || d3 == "2" || d3 == "3" || d3 == "4" || d3 == "5")))
329 || (d2 == "5" && (d3 == "0" || d3 == "1" || d3 == "2" || d3 == "3" || d3 == "4" || d3 == "5")))
331+matchesHostname = \sn name nameLen ->
332+ take nameLen sn == name && (drop nameLen sn == "" || take 1 (drop nameLen sn) == ":")
329isBadServerName = \s ->
334isBadServerName = \s ->
330 let sn = toLower (stripTrailingDot s) in
335 let sn = toLower (stripTrailingDot s) in
332 || take 1 sn == "."
337 || take 1 sn == "."
333 || take 1 sn == ":"
338 || take 1 sn == ":"
334 || containsBadUrlChar sn
339 || containsBadUrlChar sn
335− || sn == "localhost" || take 10 sn == "localhost:"
340+ || matchesHostname sn "localhost" 9
336− || sn == "localhost.localdomain" || take 22 sn == "localhost.localdomain:"
341+ || matchesHostname sn "localhost.localdomain" 21
337 || containsLocalhostSuffix sn
342 || containsLocalhostSuffix sn
338− || sn == "local" || take 6 sn == "local:"
343+ || matchesHostname sn "local" 5
339 || containsLocalSuffix sn
344 || containsLocalSuffix sn
340− || sn == "internal" || take 9 sn == "internal:"
345+ || matchesHostname sn "internal" 8
341 || containsInternalSuffix sn
346 || containsInternalSuffix sn
342− || sn == "metadata" || take 9 sn == "metadata:"
347+ || matchesHostname sn "metadata" 8
343 || take 4 sn == "127." || take 3 sn == "10."
348 || take 4 sn == "127." || take 3 sn == "10."
344 || take 8 sn == "192.168." || take 8 sn == "169.254."
349 || take 8 sn == "192.168." || take 8 sn == "169.254."
345 || take 2 sn == "0." || take 1 sn == "["
350 || take 2 sn == "0." || take 1 sn == "["
@@ -489,22 +494,12 @@ countMessagesFor = \messages toKey t ->
489 where m.receivedAt >= t - messageMaxAge
494 where m.receivedAt >= t - messageMaxAge
493− ackedIds <- *ackedIds
494− yield (do a <- ackedIds; where isFederatedOrigin a.originServer; yield a)
496−&knownMessageKeys = do
497− messages <- *messages
498− ackedIds <- *ackedIds
500− (do m <- messages; yield {messageId: m.messageId, toKey: m.toKey})
501− (do a <- ackedIds; yield {messageId: a.messageId, toKey: a.toKey}))
503−validGossipEvents : [GossipEvent] -> Bool -> Timestamp -> GossipEventType -> [{pubkey: PubkeyHex, server: Text, expiresAt: Timestamp, timestamp: Timestamp, ttl: Int<S>}]
498+validGossipEvents : [GossipEvent] -> Bool -> Timestamp -> GossipEventType -> [ValidGossipEntry]
504validGossipEvents = \events validRequest t eventType ->
499validGossipEvents = \events validRequest t eventType ->
500+ if not validRequest then []
506 e <- events
502 e <- events
508 where e.eventType == eventType
503 where e.eventType == eventType
509 where not (e.server == "")
504 where not (e.server == "")
510 where not (e.pubkey == "")
505 where not (e.pubkey == "")
@@ -583,10 +578,7 @@ sendBatchedGossipToServer = \server allEvents ->
584sendBatchedGossip : [Text] -> [GossipEvent] -> IO {network} {}
579sendBatchedGossip : [Text] -> [GossipEvent] -> IO {network} {}
585sendBatchedGossip = \peerServers allEvents ->
580sendBatchedGossip = \peerServers allEvents ->
586− if count allEvents == 0
589− sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents)
581+ sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents)
591broadcastOfflineGossip = \t peerServers expiredLocal -> do
583broadcastOfflineGossip = \t peerServers expiredLocal -> do
592 let expiredEntries = mergeByKey (\a b -> a.pubkey == b.pubkey) [] (do
584 let expiredEntries = mergeByKey (\a b -> a.pubkey == b.pubkey) [] (do
@@ -610,7 +602,7 @@ removeForward = \mid srv -> atomic do
610 where not (x.messageId == mid && x.toServer == srv)
602 where not (x.messageId == mid && x.toServer == srv)
613−retryForwardsForServer : [ForwardInfo] -> Int -> IO {network} {}
605+retryForwardsForServer : [ForwardEntry] -> Int -> IO {network} {}
614retryForwardsForServer = \entries remaining ->
606retryForwardsForServer = \entries remaining ->
615 if remaining <= 0
607 if remaining <= 0
616 then yield {}
608 then yield {}
@@ -629,7 +621,7 @@ retryForwardsForServer = \entries remaining ->
629 Err _ -> yield {}
621 Err _ -> yield {}
630 retryForwardsForServer rest (remaining - 1)
622 retryForwardsForServer rest (remaining - 1)
632−retryPendingForwards : [ForwardInfo] -> IO {network} {}
624+retryPendingForwards : [ForwardEntry] -> IO {network} {}
633retryPendingForwards = \pending -> do
625retryPendingForwards = \pending -> do
634 let servers = collectPeerServers pending (\x -> x.toServer)
626 let servers = collectPeerServers pending (\x -> x.toServer)
635 sendToEach servers (\server ->
627 sendToEach servers (\server ->
@@ -668,10 +660,9 @@ pruneAndRetry = \t -> do
668 set *lastPrunedAt = t
660 set *lastPrunedAt = t
669 pr <- pruneExpired t
661 pr <- pruneExpired t
670 forwards <- *forwards
662 forwards <- *forwards
671− let pendingForwards = do
663+ let pendingForwards = forwards
672− f <- forwards
664+ ackedIds <- *ackedIds
673− yield {toServer: f.toServer, toKey: f.toKey, fromKey: f.fromKey, encryptedBlob: f.encryptedBlob, timestamp: f.timestamp, messageId: f.messageId}
665+ let pendingAcks = do a <- ackedIds; where isFederatedOrigin a.originServer; yield a
674− pendingAcks <- &pendingAcks
675 yield {expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, pendingForwards: pendingForwards, pendingAcks: pendingAcks}
666 yield {expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, pendingForwards: pendingForwards, pendingAcks: pendingAcks}
676 broadcastOfflineGossip t result.peerServers result.expiredLocal
667 broadcastOfflineGossip t result.peerServers result.expiredLocal
677 if federationEnabled && count result.pendingForwards > 0
668 if federationEnabled && count result.pendingForwards > 0
@@ -976,7 +967,7 @@ serve = \req -> case req of
976 where p.pubkey == pubkey
967 where p.pubkey == pubkey
977 where p.expiresAt > t
968 where p.expiresAt > t
979− let foundServer = if not authorized || count valid == 0
970+ let foundServer = if not authorized
981 else if any valid (\p -> p.server == serverHostN)
972 else if any valid (\p -> p.server == serverHostN)
982 then serverHostN
973 then serverHostN
@@ -1114,12 +1105,12 @@ serve = \req -> case req of
1114 messages <- *messages
1105 messages <- *messages
1115 seqCounter <- *seqCounter
1106 seqCounter <- *seqCounter
1116 let seqTs = nextSeqTs t seqCounter
1107 let seqTs = nextSeqTs t seqCounter
1108+ ackedIds <- *ackedIds
1109+ let exists = authorized && validOrigin
1110+ && (any messages (\m -> m.messageId == messageId && m.toKey == toKey)
1111+ || any ackedIds (\a -> a.messageId == messageId && a.toKey == toKey))
1117− let recipientMsgCount = if not (authorized && validOrigin) then 0
1112+ let shouldInsert = authorized && validOrigin && not exists
1118− else countMessagesFor messages toKey t
1113+ && countMessagesFor messages toKey t < maxMessagesPerRecipient
1119− knownKeys <- &knownMessageKeys
1120− let exists = if not (authorized && validOrigin) then False {}
1121− else any knownKeys (\k -> k.messageId == messageId && k.toKey == toKey)
1122− let shouldInsert = authorized && validOrigin && not exists && recipientMsgCount < maxMessagesPerRecipient
1123 set *seqCounter = if shouldInsert then seqTs else seqCounter
1114 set *seqCounter = if shouldInsert then seqTs else seqCounter
1124 set *messages = if shouldInsert
1115 set *messages = if shouldInsert
1125 then union messages
1116 then union messages