@@ -49,6 +49,8 @@ type GossipEventType = Text where \s -> s == "online" || s == "offline"
4949
5050type GossipEvent = {eventType: GossipEventType, pubkey: Text, server: Text, timestamp: Timestamp, ttl: Int<S>}
5151
52+type ValidGossipEntry = {pubkey: PubkeyHex, server: Text, expiresAt: Timestamp, timestamp: Timestamp, ttl: Int<S>}
53+
5254type MessageStatus = Text where \s -> s == "unauthorized" || s == "rejected" || s == "delivered" || s == "federated" || s == "queued"
5355
5456type PubkeyHex = Text where \s -> isValidHex s && not (tooLong s maxPubkeyLen)
@@ -68,7 +70,7 @@ type ForwardEntry = {messageId: MessageIdHex, toServer: ServerName, createdAt: T
6870type AckedEntry = {messageId: MessageIdHex, toKey: PubkeyHex, ackedAt: Timestamp, originServer: ServerName}
6971type AuthResult = {authorized: Bool, pubkey: Text}
7072type PruneResult = {expiredLocal: [PresenceEntry], peerServers: [Text]}
71−type ForwardInfo = {messageId: MessageIdHex, toKey: PubkeyHex, fromKey: PubkeyHex, encryptedBlob: BlobHex, timestamp: Timestamp, toServer: ServerName}
73+
7274
7375-- ============================================
7476-- Persisted State
@@ -326,20 +328,23 @@ isHighOctetPrefix = \sn ->
326328 || (d2 == "4" && isDigitChar d3)
327329 || (d2 == "5" && (d3 == "0" || d3 == "1" || d3 == "2" || d3 == "3" || d3 == "4" || d3 == "5")))
328330
331+matchesHostname = \sn name nameLen ->
332+ take nameLen sn == name && (drop nameLen sn == "" || take 1 (drop nameLen sn) == ":")
333+
329334isBadServerName = \s ->
330335 let sn = toLower (stripTrailingDot s) in
331336 sn == ""
332337 || take 1 sn == "."
333338 || take 1 sn == ":"
334339 || containsBadUrlChar sn
335− || sn == "localhost" || take 10 sn == "localhost:"
336− || sn == "localhost.localdomain" || take 22 sn == "localhost.localdomain:"
340+ || matchesHostname sn "localhost" 9
341+ || matchesHostname sn "localhost.localdomain" 21
337342 || containsLocalhostSuffix sn
338− || sn == "local" || take 6 sn == "local:"
343+ || matchesHostname sn "local" 5
339344 || containsLocalSuffix sn
340− || sn == "internal" || take 9 sn == "internal:"
345+ || matchesHostname sn "internal" 8
341346 || containsInternalSuffix sn
342− || sn == "metadata" || take 9 sn == "metadata:"
347+ || matchesHostname sn "metadata" 8
343348 || take 4 sn == "127." || take 3 sn == "10."
344349 || take 8 sn == "192.168." || take 8 sn == "169.254."
345350 || take 2 sn == "0." || take 1 sn == "["
@@ -489,22 +494,12 @@ countMessagesFor = \messages toKey t ->
489494 where m.receivedAt >= t - messageMaxAge
490495 yield m)
491496
492−&pendingAcks = do
493− ackedIds <- *ackedIds
494− yield (do a <- ackedIds; where isFederatedOrigin a.originServer; yield a)
495−
496−&knownMessageKeys = do
497− messages <- *messages
498− ackedIds <- *ackedIds
499− yield (union
500− (do m <- messages; yield {messageId: m.messageId, toKey: m.toKey})
501− (do a <- ackedIds; yield {messageId: a.messageId, toKey: a.toKey}))
502497
503−validGossipEvents : [GossipEvent] -> Bool -> Timestamp -> GossipEventType -> [{pubkey: PubkeyHex, server: Text, expiresAt: Timestamp, timestamp: Timestamp, ttl: Int<S>}]
498+validGossipEvents : [GossipEvent] -> Bool -> Timestamp -> GossipEventType -> [ValidGossipEntry]
504499validGossipEvents = \events validRequest t eventType ->
505− do
500+ if not validRequest then []
501+ else do
506502 e <- events
507− where validRequest
508503 where e.eventType == eventType
509504 where not (e.server == "")
510505 where not (e.pubkey == "")
@@ -583,10 +578,7 @@ sendBatchedGossipToServer = \server allEvents ->
583578
584579sendBatchedGossip : [Text] -> [GossipEvent] -> IO {network} {}
585580sendBatchedGossip = \peerServers allEvents ->
586− if count allEvents == 0
587− then yield {}
588− else
589− sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents)
581+ sendToEach peerServers (\server -> sendBatchedGossipToServer server allEvents)
590582
591583broadcastOfflineGossip = \t peerServers expiredLocal -> do
592584 let expiredEntries = mergeByKey (\a b -> a.pubkey == b.pubkey) [] (do
@@ -610,7 +602,7 @@ removeForward = \mid srv -> atomic do
610602 where not (x.messageId == mid && x.toServer == srv)
611603 yield x
612604
613−retryForwardsForServer : [ForwardInfo] -> Int -> IO {network} {}
605+retryForwardsForServer : [ForwardEntry] -> Int -> IO {network} {}
614606retryForwardsForServer = \entries remaining ->
615607 if remaining <= 0
616608 then yield {}
@@ -629,7 +621,7 @@ retryForwardsForServer = \entries remaining ->
629621 Err _ -> yield {}
630622 retryForwardsForServer rest (remaining - 1)
631623
632−retryPendingForwards : [ForwardInfo] -> IO {network} {}
624+retryPendingForwards : [ForwardEntry] -> IO {network} {}
633625retryPendingForwards = \pending -> do
634626 let servers = collectPeerServers pending (\x -> x.toServer)
635627 sendToEach servers (\server ->
@@ -668,10 +660,9 @@ pruneAndRetry = \t -> do
668660 set *lastPrunedAt = t
669661 pr <- pruneExpired t
670662 forwards <- *forwards
671− let pendingForwards = do
672− f <- forwards
673− yield {toServer: f.toServer, toKey: f.toKey, fromKey: f.fromKey, encryptedBlob: f.encryptedBlob, timestamp: f.timestamp, messageId: f.messageId}
674− pendingAcks <- &pendingAcks
663+ let pendingForwards = forwards
664+ ackedIds <- *ackedIds
665+ let pendingAcks = do a <- ackedIds; where isFederatedOrigin a.originServer; yield a
675666 yield {expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, pendingForwards: pendingForwards, pendingAcks: pendingAcks}
676667 broadcastOfflineGossip t result.peerServers result.expiredLocal
677668 if federationEnabled && count result.pendingForwards > 0
@@ -976,7 +967,7 @@ serve = \req -> case req of
976967 where p.pubkey == pubkey
977968 where p.expiresAt > t
978969 yield p
979− let foundServer = if not authorized || count valid == 0
970+ let foundServer = if not authorized
980971 then ""
981972 else if any valid (\p -> p.server == serverHostN)
982973 then serverHostN
@@ -1114,12 +1105,12 @@ serve = \req -> case req of
11141105 messages <- *messages
11151106 seqCounter <- *seqCounter
11161107 let seqTs = nextSeqTs t seqCounter
1117− let recipientMsgCount = if not (authorized && validOrigin) then 0
1118− else countMessagesFor messages toKey t
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
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))
1112+ let shouldInsert = authorized && validOrigin && not exists
1113+ && countMessagesFor messages toKey t < maxMessagesPerRecipient
11231114 set *seqCounter = if shouldInsert then seqTs else seqCounter
11241115 set *messages = if shouldInsert
11251116 then union messages