mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-11-01 07:53:26 +00:00
Merge dda024166fddf603d824a70f068a156ab842d9d1 into 9b84b361225facd8e623f25d76f889d3dc54a879
This commit is contained in:
commit
f2e82a797c
@ -66,12 +66,24 @@ final class SecureNoiseSession: NoiseSession {
|
||||
if messageCount >= messageThreshold {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if last activity was more than 30 minutes ago
|
||||
|
||||
// Check if last activity exceeded sessionTimeout
|
||||
if Date().timeIntervalSince(lastActivityTime) > NoiseSecurityConstants.sessionTimeout {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// A session that never goes idle (a long-lived conversation with
|
||||
// steady traffic) keeps refreshing lastActivityTime forever, so the
|
||||
// check above never fires -- only sessionStartTime tracks how close
|
||||
// encrypt/decrypt are to the hard sessionExpired cutoff above. Firing
|
||||
// at 90% of sessionTimeout leaves the rekey timer's polling interval
|
||||
// (checked every 60s, see NoiseEncryptionService.rekeyCheckInterval)
|
||||
// room to complete a full handshake well before the old session
|
||||
// starts throwing sessionExpired on every call.
|
||||
if Date().timeIntervalSince(sessionStartTime) > NoiseSecurityConstants.sessionTimeout * 0.9 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@ -893,6 +893,44 @@ struct NoiseCoverageTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test("A continuously active session still schedules a rekey before it hard-expires")
|
||||
func continuouslyActiveSessionStillNeedsRenegotiationBeforeExpiry() throws {
|
||||
// A session with steady traffic never goes idle, so lastActivityTime
|
||||
// stays fresh right up to the moment sessionStartTime crosses the
|
||||
// hard sessionTimeout cutoff above and encrypt/decrypt start throwing
|
||||
// sessionExpired on every call. needsRenegotiation() has to notice
|
||||
// the session is old on its own -- it can't rely on the idle check,
|
||||
// because there is no idle time to find.
|
||||
let session = SecureNoiseSession(
|
||||
peerID: alicePeerID,
|
||||
role: .initiator,
|
||||
keychain: keychain,
|
||||
localStaticKey: aliceStaticKey
|
||||
)
|
||||
let responder = SecureNoiseSession(
|
||||
peerID: bobPeerID,
|
||||
role: .responder,
|
||||
keychain: keychain,
|
||||
localStaticKey: bobStaticKey
|
||||
)
|
||||
try establishSessions(initiator: session, responder: responder)
|
||||
|
||||
// Just under the hard cutoff, but past the 90% rekey threshold.
|
||||
session.setSessionStartTimeForTesting(
|
||||
Date().addingTimeInterval(-(NoiseSecurityConstants.sessionTimeout * 0.95))
|
||||
)
|
||||
session.setLastActivityTimeForTesting(Date())
|
||||
session.setMessageCountForTesting(0)
|
||||
|
||||
#expect(session.needsRenegotiation())
|
||||
|
||||
// The session is still within its hard cutoff, so it must keep
|
||||
// working right up until a rekey actually replaces it -- the fix is
|
||||
// to schedule the rekey earlier, not to expire the session sooner.
|
||||
let ciphertext = try session.encrypt(Data("still working".utf8))
|
||||
#expect(try responder.decrypt(ciphertext) == Data("still working".utf8))
|
||||
}
|
||||
|
||||
@Test("Rate limiter handles global message caps and per-peer resets")
|
||||
func rateLimiterGlobalMessageCapAndReset() async throws {
|
||||
let globalLimiter = NoiseRateLimiter()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user