@@ -76,7 +76,7 @@ route AuthApi where
76 = VerifyAuth
76 = VerifyAuth
78route ClientApi where
78route ClientApi where
79− GET {cursor: Int} /poll headers {authorization: Text}
79+ GET {cursor: Int, timeout: Int} /poll headers {authorization: Text}
80 -> {events: [PollEvent], cursor: Int, authorized: Bool}
80 -> {events: [PollEvent], cursor: Int, authorized: Bool}
@@ -524,12 +524,12 @@ serve = \req -> case req of
524 else if not (isValidHex pubkey) || not (isValidHex signature)
524 else if not (isValidHex pubkey) || not (isValidHex signature)
525 then False {}
525 then False {}
526 else verify (bytesFromHex pubkey) (textToBytes challenge) (bytesFromHex signature)
526 else verify (bytesFromHex pubkey) (textToBytes challenge) (bytesFromHex signature)
527− set *challenges = if sigValid
527+ set *challenges = case matched of
528− then do
528+ Just {value: _} -> do
529 c <- challenges
529 c <- challenges
530 where not (c.pubkey == pubkey && c.challenge == challenge)
530 where not (c.pubkey == pubkey && c.challenge == challenge)
532− else challenges
532+ Nothing {} -> challenges
533 let existingForKey = do
533 let existingForKey = do
534 s <- sessions
534 s <- sessions
535 where s.pubkey == pubkey
535 where s.pubkey == pubkey
@@ -591,43 +591,49 @@ serve = \req -> case req of
591 where not (p.pubkey == pubkey)
591 where not (p.pubkey == pubkey)
594− Poll {cursor, authorization, respond} -> do
594+ Poll {cursor, timeout, authorization, respond} -> do
596+ let clampedTimeout = if timeout < 0 then 0 else if timeout > 60000 then 60000 else timeout
597+ let deadline = t + clampedTimeout
596 let token = extractToken authorization
598 let token = extractToken authorization
597 result <- atomic do
599 result <- atomic do
598− pr <- maybePrune t
601+ pr <- maybePrune tNow
599 sessions <- *sessions
602 sessions <- *sessions
600 messages <- *messages
603 messages <- *messages
601 seqCounter <- *seqCounter
604 seqCounter <- *seqCounter
602− let session = lookupSession sessions token t
605+ let session = lookupSession sessions token tNow
603 let clampedCursor = if cursor < 0 then 0 else if cursor > seqCounter then seqCounter else cursor
606 let clampedCursor = if cursor < 0 then 0 else if cursor > seqCounter then seqCounter else cursor
604 let matchingMsgs = case session of
607 let matchingMsgs = case session of
605 Nothing {} -> []
608 Nothing {} -> []
606 Just {value: s} -> do
609 Just {value: s} -> do
607 m <- messages
610 m <- messages
608 where m.toKey == s.pubkey
611 where m.toKey == s.pubkey
609− where m.receivedAt >= t - messageMaxAge
612+ where m.receivedAt >= tNow - messageMaxAge
610 where m.receivedAt > clampedCursor
613 where m.receivedAt > clampedCursor
612 let limitedMsgs = fold (\acc m ->
615 let limitedMsgs = fold (\acc m ->
613 if count acc >= maxPollEvents then acc
616 if count acc >= maxPollEvents then acc
614 else union acc [m]) [] matchingMsgs
617 else union acc [m]) [] matchingMsgs
617− yield {id: m.messageId, eventType: "message",
618− payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
619− encryptedBlob: m.encryptedBlob,
620− timestamp: m.timestamp}}
621− let lastReceivedAt = fold (\acc m -> if m.receivedAt > acc then m.receivedAt else acc) clampedCursor limitedMsgs
622 let authorized = case session of
618 let authorized = case session of
623 Nothing {} -> False {}
619 Nothing {} -> False {}
624 _ -> True {}
620 _ -> True {}
621+ if authorized && count limitedMsgs == 0 && tNow < deadline
626+ yield {id: m.messageId, eventType: "message",
627+ payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
628+ encryptedBlob: m.encryptedBlob,
629+ timestamp: m.timestamp}}
630+ let lastReceivedAt = fold (\acc m -> if m.receivedAt > acc then m.receivedAt else acc) clampedCursor limitedMsgs
625− let newCursor = case session of
631+ let newCursor = case session of
626− Nothing {} -> -1
632+ Nothing {} -> -1
627− _ -> if count limitedMsgs >= maxPollEvents
633+ _ -> if count limitedMsgs >= maxPollEvents
628− then lastReceivedAt
634+ then lastReceivedAt
629− else if seqCounter > clampedCursor then seqCounter else clampedCursor
635+ else if seqCounter > clampedCursor then seqCounter else clampedCursor
630− yield {events: evts, cursor: newCursor, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
636+ yield {events: evts, cursor: newCursor, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
631 respond {events: result.events, cursor: result.cursor, authorized: result.authorized}
637 respond {events: result.events, cursor: result.cursor, authorized: result.authorized}
632 broadcastOfflineGossip t result.peerServers result.expiredLocal
638 broadcastOfflineGossip t result.peerServers result.expiredLocal
@@ -709,8 +715,7 @@ serve = \req -> case req of
710 AckMessages {messageIds, authorization, respond} -> do
716 AckMessages {messageIds, authorization, respond} -> do
712− let dedupedIds = if count messageIds > maxMessageIds then []
713− else fold (\acc mid ->
718+ let dedupedIds = fold (\acc mid ->
714 if mid == "" then acc
719 if mid == "" then acc
715 else if count acc >= maxMessageIds then acc
720 else if count acc >= maxMessageIds then acc
716 else if tooLong mid maxMessageIdLen then acc
721 else if tooLong mid maxMessageIdLen then acc
@@ -1019,6 +1024,12 @@ serve = \req -> case req of
1019 where o.server == normalizeServerName e.server
1024 where o.server == normalizeServerName e.server
1020 where o.timestamp > e.timestamp
1025 where o.timestamp > e.timestamp
1021 yield o) > 0)
1026 yield o) > 0)
1027+ where not (e.eventType == "offline" && count (do
1029+ where o.pubkey == normalizeHex e.pubkey
1030+ where o.server == normalizeServerName e.server
1031+ where o.timestamp > e.timestamp
1023 let effectiveEvents = do
1034 let effectiveEvents = do
1024 e <- validEvents
1035 e <- validEvents
@@ -1030,12 +1041,9 @@ serve = \req -> case req of
1030 else yield {}
1041 else yield {}
1031 if validRequest && cappedHops > 1 && not (federationSecret == "") && count effectiveEvents > 0
1042 if validRequest && cappedHops > 1 && not (federationSecret == "") && count effectiveEvents > 0
1033− let senderServers = fold (\acc e ->
1034− if count (do a <- acc; where a == e.server; yield a) > 0 then acc
1035− else union acc [e.server]) (if fromServer == "" then [] else [fromServer]) effectiveEvents
1036 let targets = do
1044 let targets = do
1037 s <- gossipResult.gossipPeerServers
1045 s <- gossipResult.gossipPeerServers
1038− where count (do ss <- senderServers; where ss == s; yield ss) == 0
1046+ where not (s == fromServer)
1040 sendToEach targets (\server ->
1048 sendToEach targets (\server ->
1041 fetch (federationScheme ++ server) (RecvGossip {
1049 fetch (federationScheme ++ server) (RecvGossip {
@@ -1094,8 +1102,7 @@ serve = \req -> case req of
1094 let originServer = normalizeServerName originServer
1102 let originServer = normalizeServerName originServer
1095 t <- now
1103 t <- now
1096 let authorized = verifyFederationAuth authorization
1104 let authorized = verifyFederationAuth authorization
1097− let dedupedIds = if count messageIds > maxMessageIds then []
1098− else fold (\acc mid ->
1105+ let dedupedIds = fold (\acc mid ->
1099 if mid == "" then acc
1106 if mid == "" then acc
1100 else if count acc >= maxMessageIds then acc
1107 else if count acc >= maxMessageIds then acc
1101 else if tooLong mid maxMessageIdLen then acc
1108 else if tooLong mid maxMessageIdLen then acc