@@ -222,11 +222,10 @@ sToMs = \s -> stripUnit s * 1000
222-- and stripped of trailing dots, with a deny-list filter (`isBadServerName`)
222-- and stripped of trailing dots, with a deny-list filter (`isBadServerName`)
223-- applied where SSRF is a concern.
223-- applied where SSRF is a concern.
225−-- One event in a /poll response. `eventType` is currently always "message"; the
225+-- One event in a /poll response. The payload is the opaque cipher blob plus
226−-- payload is the cipher blob plus delivery metadata for the recipient.
226+-- delivery metadata for the recipient; the server cannot read the blob.
227type PollEvent = {
227type PollEvent = {
228 id: MessageIdHex,
228 id: MessageIdHex,
230 payload: {encryptedBlob: BlobHex, timestamp: Timestamp, toKey: PubkeyHex, expiresAt: Timestamp}
229 payload: {encryptedBlob: BlobHex, timestamp: Timestamp, toKey: PubkeyHex, expiresAt: Timestamp}
@@ -1566,7 +1565,7 @@ pollOnce = \authorization cursor cursorWasReset clientIp serverGen respond t ->
1567-- One pass: collect events at `t`. If empty, retry-wait on `pollWakeup`
1566-- One pass: collect events at `t`. If empty, retry-wait on `pollWakeup`
1568-- (bumped by send/heartbeat) and re-collect once at the new wall time.
1567-- (bumped by send/heartbeat) and re-collect once at the new wall time.
1569−doPoll : {clampedCursor: Int, pendingAcks: [AckedEntry], pubkey: PubkeyHex, startWakeup: Timestamp} -> Int<Ms> -> IO {r *pollWakeup, clock} {cursor: Int<Ms>, events: [{eventType: Text, id: MessageIdHex, payload: {encryptedBlob: BlobHex, expiresAt: Timestamp, timestamp: Timestamp, toKey: PubkeyHex}}], hasMore: Bool}
1568+doPoll : {clampedCursor: Int, pendingAcks: [AckedEntry], pubkey: PubkeyHex, startWakeup: Timestamp} -> Int<Ms> -> IO {r *pollWakeup, clock} {cursor: Int<Ms>, events: [{id: MessageIdHex, payload: {encryptedBlob: BlobHex, expiresAt: Timestamp, timestamp: Timestamp, toKey: PubkeyHex}}], hasMore: Bool}
1570doPoll = \s t -> do
1569doPoll = \s t -> do
1571 let collectAt = \tnow -> atomic (do
1570 let collectAt = \tnow -> atomic (do
1572 msgs <- *messages
1571 msgs <- *messages
@@ -1582,7 +1581,7 @@ doPoll = \s t -> do
1582-- Pull this pubkey's unexpired messages newer than `cursor`, sort by
1581-- Pull this pubkey's unexpired messages newer than `cursor`, sort by
1583-- receivedAt, take up to `maxPollEvents`, and report `hasMore` if truncated.
1582-- receivedAt, take up to `maxPollEvents`, and report `hasMore` if truncated.
1584collectPollEvents : [Message] -> PubkeyHex -> Timestamp -> Timestamp -> {events: [PollEvent], cursor: Timestamp, hasMore: Bool}
1583collectPollEvents : [Message] -> PubkeyHex -> Timestamp -> Timestamp -> {events: [PollEvent], cursor: Timestamp, hasMore: Bool}
1585−collectPollEvents = \messages pubkey cursor t -> (\myMsgs -> (\limited -> {events: pluck limited (\m -> {id: m.messageId, eventType: "message", payload: {m.toKey, m.encryptedBlob, m.timestamp, m.expiresAt}}), cursor: fold (\acc m -> max acc m.receivedAt) cursor limited, hasMore: count myMsgs > count limited}) (takeRelation maxPollEvents (sortBy (\m -> m.receivedAt) myMsgs))) (filter messages (\m -> m.toKey == pubkey && m.expiresAt > t && m.receivedAt > cursor))
1584+collectPollEvents = \messages pubkey cursor t -> (\myMsgs -> (\limited -> {events: pluck limited (\m -> {id: m.messageId, payload: {m.toKey, m.encryptedBlob, m.timestamp, m.expiresAt}}), cursor: fold (\acc m -> max acc m.receivedAt) cursor limited, hasMore: count myMsgs > count limited}) (takeRelation maxPollEvents (sortBy (\m -> m.receivedAt) myMsgs))) (filter messages (\m -> m.toKey == pubkey && m.expiresAt > t && m.receivedAt > cursor))
1587-- Treat the supplied cursor as an ack: drop all messages with
1586-- Treat the supplied cursor as an ack: drop all messages with
1588-- receivedAt <= cursor, plus their pending forwards, and record federated
1587-- receivedAt <= cursor, plus their pending forwards, and record federated