@@ -68,7 +68,7 @@ route FederationApi where
68 POST {toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Int, originServer: Text, messageId: Text} /forward headers {authorization: Text}
68 POST {toKey: Text, fromKey: Text, encryptedBlob: Text, timestamp: Int, originServer: Text, messageId: Text} /forward headers {authorization: Text}
69 -> {ok: Bool}
69 -> {ok: Bool}
70 = ForwardMessage
70 = ForwardMessage
71− POST {messageIds: [Text], originServer: Text} /ack headers {authorization: Text}
71+ POST {messageIds: [Text], originServer: Text, fromServer: Text} /ack headers {authorization: Text}
72 -> {ok: Bool}
72 -> {ok: Bool}
73 = FederationAck
73 = FederationAck
@@ -196,6 +196,19 @@ serve = \req -> case req of
196 if sigValid
196 if sigValid
197 then respond {token: token, expiresAt: expiry}
197 then respond {token: token, expiresAt: expiry}
198 else respond {token: "", expiresAt: 0}
198 else respond {token: "", expiresAt: 0}
199+ if sigValid && not (federationSecret == "")
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})
200 Poll {authorization, respond} -> do
213 Poll {authorization, respond} -> do
@@ -306,13 +319,13 @@ serve = \req -> case req of
306 httpPost (federationScheme ++ server ++ "/federation/ack")
319 httpPost (federationScheme ++ server ++ "/federation/ack")
307 {authorization: "Bearer " ++ federationSecret}
320 {authorization: "Bearer " ++ federationSecret}
308 {messageIds: (do m <- fedMessages; where m.originServer == server; yield m.messageId),
321 {messageIds: (do m <- fedMessages; where m.originServer == server; yield m.messageId),
309− originServer: server})
322+ originServer: server, fromServer: serverHost})
310 else yield {}
323 else yield {}
311 respond {ok: result.ok}
324 respond {ok: result.ok}
313 LookupPresence {pubkey, authorization, respond} -> do
326 LookupPresence {pubkey, authorization, respond} -> do
315− foundServer <- atomic do
328+ result <- atomic do
316 pruneExpired t
329 pruneExpired t
317 sessions <- *sessions
330 sessions <- *sessions
318 presence <- *presence
331 presence <- *presence
@@ -333,8 +346,13 @@ serve = \req -> case req of
333 yield p) of
346 yield p) of
334 Just {value: p} -> p.server
347 Just {value: p} -> p.server
335 Nothing {} -> fold (\_ p -> p.server) "" valid
348 Nothing {} -> fold (\_ p -> p.server) "" valid
349+ let authorized = case session of
350+ Nothing {} -> False {}
336− yield foundServer
352+ yield {foundServer: foundServer, authorized: authorized}
353+ if result.authorized
337− respond {online: not (foundServer == ""), server: foundServer}
354+ then respond {online: not (result.foundServer == ""), server: result.foundServer}
355+ else respond {online: False {}, server: "unauthorized"}
339 RecvGossip {events, hopsRemaining, authorization, respond} -> do
357 RecvGossip {events, hopsRemaining, authorization, respond} -> do
@@ -346,19 +364,30 @@ serve = \req -> case req of
346 where not (e.server == serverHost)
364 where not (e.server == serverHost)
347 where e.timestamp <= t
365 where e.timestamp <= t
348 where e.timestamp + (clampTtl e.ttl) * 1000 > t
366 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}
350 let offlineEntries = do
368 let offlineEntries = do
351 e <- events
369 e <- events
352 where e.eventType == "offline"
370 where e.eventType == "offline"
353 where not (e.server == serverHost)
371 where not (e.server == serverHost)
354 where e.timestamp <= t
372 where e.timestamp <= t
355 where t - e.timestamp < (clampTtl e.ttl) * 1000
373 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
379+ where o.pubkey == e.pubkey
380+ where o.server == e.server
381+ where o.timestamp > e.timestamp
383+ yield {pubkey: e.pubkey, server: e.server, expiresAt: e.expiresAt}
357 let affectedKeys = union
384 let affectedKeys = union
359 e <- onlineEntries
386 e <- onlineEntries
360 yield {pubkey: e.pubkey, server: e.server})
387 yield {pubkey: e.pubkey, server: e.server})
361− offlineEntries
389+ e <- offlineEntries
390+ yield {pubkey: e.pubkey, server: e.server})
362 let deduped = fold (\acc e ->
391 let deduped = fold (\acc e ->
363 if count (do
392 if count (do
@@ -372,7 +401,7 @@ serve = \req -> case req of
373 where not (a.pubkey == e.pubkey && a.server == e.server)
402 where not (a.pubkey == e.pubkey && a.server == e.server)
375− [e]) [] onlineEntries
404+ [e]) [] filteredOnline
376 atomic do
405 atomic do
377 pruneExpired t
406 pruneExpired t
378 presence <- *presence
407 presence <- *presence
@@ -410,6 +439,7 @@ serve = \req -> case req of
410 ForwardMessage {toKey, fromKey, encryptedBlob, timestamp, originServer, messageId, authorization, respond} -> do
439 ForwardMessage {toKey, fromKey, encryptedBlob, timestamp, originServer, messageId, authorization, respond} -> do
412 let authorized = verifyFederationAuth authorization
441 let authorized = verifyFederationAuth authorization
442+ let validOrigin = not (originServer == "") && not (originServer == serverHost)
413 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t - messageMaxAge else timestamp
443 let clampedTs = if timestamp > t then t else if timestamp < t - messageMaxAge then t - messageMaxAge else timestamp
414 atomic do
444 atomic do
415 pruneExpired t
445 pruneExpired t
@@ -419,18 +449,18 @@ serve = \req -> case req of
419 where m.messageId == messageId
449 where m.messageId == messageId
420 where m.timestamp > t - messageMaxAge
450 where m.timestamp > t - messageMaxAge
421 yield m) > 0
451 yield m) > 0
422− let shouldInsert = authorized && not exists
452+ let shouldInsert = authorized && validOrigin && not exists
423 set *messages = if shouldInsert
453 set *messages = if shouldInsert
424 then union messages
454 then union messages
425 [{messageId: messageId, toKey: toKey, fromKey: fromKey,
455 [{messageId: messageId, toKey: toKey, fromKey: fromKey,
426 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: originServer}]
456 encryptedBlob: encryptedBlob, timestamp: clampedTs, originServer: originServer}]
427 else messages
457 else messages
428− respond {ok: authorized}
458+ respond {ok: authorized && validOrigin}
430− FederationAck {messageIds, originServer, authorization, respond} -> do
460+ FederationAck {messageIds, originServer, fromServer, authorization, respond} -> do
432 let authorized = verifyFederationAuth authorization
462 let authorized = verifyFederationAuth authorization
433− let validAck = authorized && originServer == serverHost
463+ let validAck = authorized && originServer == serverHost && not (fromServer == "") && not (fromServer == serverHost)
434 atomic do
464 atomic do
435 pruneExpired t
465 pruneExpired t
436 messages <- *messages
466 messages <- *messages
@@ -446,6 +476,12 @@ serve = \req -> case req of
446 where p.server == serverHost
476 where p.server == serverHost
447 where p.expiresAt > t
477 where p.expiresAt > t
448 yield p) == 0
478 yield p) == 0
481+ where p.pubkey == m.toKey
482+ where p.server == fromServer
483+ where p.expiresAt > t
450 else messages
486 else messages
451 respond {ok: validAck}
487 respond {ok: validAck}