@@ -68,7 +68,7 @@ route FederationApi where
6868 POST {toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Int, originServer: Text, messageId: Text} /forward headers {authorization: Text}
6969 -> {ok: Bool}
7070 = ForwardMessage
71− POST {messageIds: [Text], originServer: Text} /ack headers {authorization: Text}
71+ POST {messageIds: [Text], originServer: Text, fromServer: Text} /ack headers {authorization: Text}
7272 -> {ok: Bool}
7373 = FederationAck
7474
@@ -196,6 +196,19 @@ serve = \req -> case req of
196196 if sigValid
197197 then respond {token: token, expiresAt: expiry}
198198 else respond {token: "", expiresAt: 0}
199+ if sigValid && not (federationSecret == "")
200+ then do
201+ peerServers <- atomic do
202+ presence <- *presence
203+ yield (fold (\acc p ->
204+ if p.server == serverHost then acc
205+ else if count (do a <- acc; where a == p.server; yield a) > 0 then acc
206+ else union acc [p.server]) [] presence)
207+ sendToEach peerServers (\server ->
208+ httpPost (federationScheme ++ server ++ "/federation/gossip")
209+ {authorization: "Bearer " ++ federationSecret}
210+ {events: [{eventType: "online", pubkey: pubkey, server: serverHost, timestamp: t, ttl: 3600}], hopsRemaining: 2})
211+ else yield {}
199212
200213 Poll {authorization, respond} -> do
201214 t <- now
@@ -306,13 +319,13 @@ serve = \req -> case req of
306319 httpPost (federationScheme ++ server ++ "/federation/ack")
307320 {authorization: "Bearer " ++ federationSecret}
308321 {messageIds: (do m <- fedMessages; where m.originServer == server; yield m.messageId),
309− originServer: server})
322+ originServer: server, fromServer: serverHost})
310323 else yield {}
311324 respond {ok: result.ok}
312325
313326 LookupPresence {pubkey, authorization, respond} -> do
314327 t <- now
315− foundServer <- atomic do
328+ result <- atomic do
316329 pruneExpired t
317330 sessions <- *sessions
318331 presence <- *presence
@@ -333,8 +346,13 @@ serve = \req -> case req of
333346 yield p) of
334347 Just {value: p} -> p.server
335348 Nothing {} -> fold (\_ p -> p.server) "" valid
336− yield foundServer
337− respond {online: not (foundServer == ""), server: foundServer}
349+ let authorized = case session of
350+ Nothing {} -> False {}
351+ _ -> True {}
352+ yield {foundServer: foundServer, authorized: authorized}
353+ if result.authorized
354+ then respond {online: not (result.foundServer == ""), server: result.foundServer}
355+ else respond {online: False {}, server: "unauthorized"}
338356
339357 RecvGossip {events, hopsRemaining, authorization, respond} -> do
340358 t <- now
@@ -346,19 +364,30 @@ serve = \req -> case req of
346364 where not (e.server == serverHost)
347365 where e.timestamp <= t
348366 where e.timestamp + (clampTtl e.ttl) * 1000 > t
349− yield {pubkey: e.pubkey, server: e.server, expiresAt: e.timestamp + (clampTtl e.ttl) * 1000}
367+ yield {pubkey: e.pubkey, server: e.server, expiresAt: e.timestamp + (clampTtl e.ttl) * 1000, timestamp: e.timestamp}
350368 let offlineEntries = do
351369 e <- events
352370 where e.eventType == "offline"
353371 where not (e.server == serverHost)
354372 where e.timestamp <= t
355373 where t - e.timestamp < (clampTtl e.ttl) * 1000
356− yield {pubkey: e.pubkey, server: e.server}
374+ yield {pubkey: e.pubkey, server: e.server, timestamp: e.timestamp}
375+ let filteredOnline = do
376+ e <- onlineEntries
377+ where count (do
378+ o <- offlineEntries
379+ where o.pubkey == e.pubkey
380+ where o.server == e.server
381+ where o.timestamp > e.timestamp
382+ yield o) == 0
383+ yield {pubkey: e.pubkey, server: e.server, expiresAt: e.expiresAt}
357384 let affectedKeys = union
358385 (do
359386 e <- onlineEntries
360387 yield {pubkey: e.pubkey, server: e.server})
361− offlineEntries
388+ (do
389+ e <- offlineEntries
390+ yield {pubkey: e.pubkey, server: e.server})
362391 let deduped = fold (\acc e ->
363392 if count (do
364393 a <- acc
@@ -372,7 +401,7 @@ serve = \req -> case req of
372401 a <- acc
373402 where not (a.pubkey == e.pubkey && a.server == e.server)
374403 yield a)
375− [e]) [] onlineEntries
404+ [e]) [] filteredOnline
376405 atomic do
377406 pruneExpired t
378407 presence <- *presence
@@ -410,6 +439,7 @@ serve = \req -> case req of
410439 ForwardMessage {toKey, fromKey, encryptedBlob, timestamp, originServer, messageId, authorization, respond} -> do
411440 t <- now
412441 let authorized = verifyFederationAuth authorization
442+ let validOrigin = not (originServer == "") && not (originServer == serverHost)
413443 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t - messageMaxAge else timestamp
414444 atomic do
415445 pruneExpired t
@@ -419,18 +449,18 @@ serve = \req -> case req of
419449 where m.messageId == messageId
420450 where m.timestamp > t - messageMaxAge
421451 yield m) > 0
422− let shouldInsert = authorized && not exists
452+ let shouldInsert = authorized && validOrigin && not exists
423453 set *messages = if shouldInsert
424454 then union messages
425455 [{messageId: messageId, toKey: toKey, fromKey: fromKey,
426456 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: originServer}]
427457 else messages
428− respond {ok: authorized}
458+ respond {ok: authorized && validOrigin}
429459
430− FederationAck {messageIds, originServer, authorization, respond} -> do
460+ FederationAck {messageIds, originServer, fromServer, authorization, respond} -> do
431461 t <- now
432462 let authorized = verifyFederationAuth authorization
433− let validAck = authorized && originServer == serverHost
463+ let validAck = authorized && originServer == serverHost && not (fromServer == "") && not (fromServer == serverHost)
434464 atomic do
435465 pruneExpired t
436466 messages <- *messages
@@ -446,6 +476,12 @@ serve = \req -> case req of
446476 where p.server == serverHost
447477 where p.expiresAt > t
448478 yield p) == 0
479+ where count (do
480+ p <- presence
481+ where p.pubkey == m.toKey
482+ where p.server == fromServer
483+ where p.expiresAt > t
484+ yield p) > 0
449485 yield m)
450486 else messages
451487 respond {ok: validAck}