on master help sign in
Fix 7 server.knot bugs: hex validation, poll authorization, gossip fromServer check, and message age calculation
75f4a12iko
server.knot+15−10
@@ -55,7 +55,7 @@ route AuthApi where
55
55
56route ClientApi where
56route ClientApi where
57 GET {cursor: Int} /poll headers {authorization: Text}
57 GET {cursor: Int} /poll headers {authorization: Text}
58− -> {events: [PollEvent], cursor: Int}
58+ -> {events: [PollEvent], cursor: Int, authorized: Bool}
59 = Poll
59 = Poll
60 /messages
60 /messages
61 POST {to: Text, encryptedBlob: Text, timestamp: Int} / headers {authorization: Text}
61 POST {to: Text, encryptedBlob: Text, timestamp: Int} / headers {authorization: Text}
@@ -163,7 +163,7 @@ pruneExpired = \t -> do
163 messages <- *messages
163 messages <- *messages
164 set *messages = do
164 set *messages = do
165 m <- messages
165 m <- messages
166− where m.timestamp >= t - messageMaxAge
166+ where m.receivedAt >= t - messageMaxAge
167 yield m
167 yield m
168 yield {expiredLocal: (do
168 yield {expiredLocal: (do
169 p <- presenceBefore
169 p <- presenceBefore
@@ -198,7 +198,7 @@ broadcastOfflineGossip = \t peerServers expiredLocal -> do
198serve = \req -> case req of
198serve = \req -> case req of
199
199
200 ReqChallenge {pubkey, respond} ->
200 ReqChallenge {pubkey, respond} ->
201− if pubkey == "" || tooLong pubkey maxPubkeyLen
201+ if pubkey == "" || tooLong pubkey maxPubkeyLen || not (isValidHex pubkey)
202 then respond {challenge: ""}
202 then respond {challenge: ""}
203 else do
203 else do
204 challenge <- genToken
204 challenge <- genToken
@@ -297,24 +297,27 @@ serve = \req -> case req of
297 Just {value: s} -> do
297 Just {value: s} -> do
298 m <- messages
298 m <- messages
299 where m.toKey == s.pubkey
299 where m.toKey == s.pubkey
300− where m.timestamp >= t - messageMaxAge
300+ where m.receivedAt >= t - messageMaxAge
301 where m.receivedAt > cursor
301 where m.receivedAt > cursor
302 yield {id: m.messageId, eventType: "message",
302 yield {id: m.messageId, eventType: "message",
303 payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
303 payload: toJson {toKey: m.toKey, fromKey: m.fromKey,
304 encryptedBlob: m.encryptedBlob,
304 encryptedBlob: m.encryptedBlob,
305 timestamp: m.timestamp}}
305 timestamp: m.timestamp}}
306+ let authorized = case session of
307+ Nothing {} -> False {}
308+ _ -> True {}
306 let newCursor = case session of
309 let newCursor = case session of
307 Nothing {} -> -1
310 Nothing {} -> -1
308 _ -> if seqCounter > cursor then seqCounter else cursor
311 _ -> if seqCounter > cursor then seqCounter else cursor
309− yield {events: evts, cursor: newCursor, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
312+ yield {events: evts, cursor: newCursor, authorized: authorized, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers}
310− respond {events: result.events, cursor: result.cursor}
313+ respond {events: result.events, cursor: result.cursor, authorized: result.authorized}
311 broadcastOfflineGossip t result.peerServers result.expiredLocal
314 broadcastOfflineGossip t result.peerServers result.expiredLocal
312
315
313 SendMessage {to, encryptedBlob, timestamp, authorization, respond} -> do
316 SendMessage {to, encryptedBlob, timestamp, authorization, respond} -> do
314 t <- now
317 t <- now
315 msgId <- genToken
318 msgId <- genToken
316 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t else timestamp
319 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t else timestamp
317− let validInput = not (to == "") && not (encryptedBlob == "") && not (tooLong to maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen)
320+ let validInput = not (to == "") && not (encryptedBlob == "") && isValidHex to && not (tooLong to maxPubkeyLen) && not (tooLong encryptedBlob maxBlobLen)
318 result <- atomic do
321 result <- atomic do
319 pr <- pruneExpired t
322 pr <- pruneExpired t
320 sessions <- *sessions
323 sessions <- *sessions
@@ -450,13 +453,14 @@ serve = \req -> case req of
450 t <- now
453 t <- now
451 let authorized = verifyFederationAuth authorization
454 let authorized = verifyFederationAuth authorization
452 let cappedHops = if hopsRemaining > 5 then 5 else hopsRemaining
455 let cappedHops = if hopsRemaining > 5 then 5 else hopsRemaining
453− let validRequest = authorized && cappedHops >= 1 && not (fromServer == "") && not (tooLong fromServer maxPubkeyLen) && count events <= maxGossipEvents
456+ let validRequest = authorized && cappedHops >= 1 && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen) && count events <= maxGossipEvents
454 let onlineEntries = do
457 let onlineEntries = do
455 e <- events
458 e <- events
456 where validRequest
459 where validRequest
457 where e.eventType == "online"
460 where e.eventType == "online"
458 where not (e.server == "")
461 where not (e.server == "")
459 where not (e.pubkey == "")
462 where not (e.pubkey == "")
463+ where isValidHex e.pubkey
460 where not (tooLong e.pubkey maxPubkeyLen)
464 where not (tooLong e.pubkey maxPubkeyLen)
461 where not (tooLong e.server maxPubkeyLen)
465 where not (tooLong e.server maxPubkeyLen)
462 where not (e.server == serverHost)
466 where not (e.server == serverHost)
@@ -469,6 +473,7 @@ serve = \req -> case req of
469 where e.eventType == "offline"
473 where e.eventType == "offline"
470 where not (e.server == "")
474 where not (e.server == "")
471 where not (e.pubkey == "")
475 where not (e.pubkey == "")
476+ where isValidHex e.pubkey
472 where not (tooLong e.pubkey maxPubkeyLen)
477 where not (tooLong e.pubkey maxPubkeyLen)
473 where not (tooLong e.server maxPubkeyLen)
478 where not (tooLong e.server maxPubkeyLen)
474 where not (e.server == serverHost)
479 where not (e.server == serverHost)
@@ -623,7 +628,7 @@ serve = \req -> case req of
623 let exists = count (do
628 let exists = count (do
624 m <- messages
629 m <- messages
625 where m.messageId == messageId
630 where m.messageId == messageId
626− where m.timestamp >= t - messageMaxAge
631+ where m.receivedAt >= t - messageMaxAge
627 yield m) > 0
632 yield m) > 0
628 let shouldInsert = authorized && validOrigin && validFields && not exists
633 let shouldInsert = authorized && validOrigin && validFields && not exists
629 set *seqCounter = if shouldInsert then seqTs else seqCounter
634 set *seqCounter = if shouldInsert then seqTs else seqCounter
@@ -644,7 +649,7 @@ serve = \req -> case req of
644 else if count acc >= maxMessageIds then acc
649 else if count acc >= maxMessageIds then acc
645 else if count (do a <- acc; where a == mid; yield a) > 0 then acc
650 else if count (do a <- acc; where a == mid; yield a) > 0 then acc
646 else union acc [mid]) [] messageIds
651 else union acc [mid]) [] messageIds
647− let validAck = authorized && originServer == serverHost && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen) && count messageIds <= maxMessageIds
652+ let validAck = authorized && originServer == serverHost && not (fromServer == "") && not (fromServer == serverHost) && not (tooLong fromServer maxPubkeyLen) && count dedupedIds <= maxMessageIds
648 pruneResult <- atomic do
653 pruneResult <- atomic do
649 pr <- pruneExpired t
654 pr <- pruneExpired t
650 messages <- *messages
655 messages <- *messages