mirror of
https://github.com/signalapp/libsignal.git
synced 2026-04-26 01:35:22 +02:00
protocol: Throw SessionNotFound for an expired unacknowledged session
For the most part this should happen transparently without any explicit adoption, like the previous change, but for Java code the NoSessionException is now properly declared on SessionCipher.encrypt. (This was always technically possible, but clients were expected to have previously checked for session validity before using SessionCipher; now that there's an expiration involved, that's not strictly possible.)
This commit is contained in:
@@ -8,7 +8,7 @@ use futures_util::FutureExt;
|
||||
use libsignal_protocol::*;
|
||||
use rand::rngs::OsRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::time::SystemTime;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use support::*;
|
||||
|
||||
type TestResult = Result<(), SignalProtocolError>;
|
||||
@@ -1959,6 +1959,94 @@ fn test_zero_is_a_valid_prekey_id() -> TestResult {
|
||||
.expect("sync")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unacknowledged_sessions_eventually_expire() -> TestResult {
|
||||
async {
|
||||
const WELL_PAST_EXPIRATION: Duration = Duration::from_secs(60 * 60 * 24 * 90);
|
||||
|
||||
let mut csprng = OsRng;
|
||||
let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1.into());
|
||||
|
||||
let mut alice_store = TestStoreBuilder::new().store;
|
||||
let bob_store_builder = TestStoreBuilder::new()
|
||||
.with_pre_key(0.into())
|
||||
.with_signed_pre_key(0.into())
|
||||
.with_kyber_pre_key(0.into());
|
||||
|
||||
let bob_pre_key_bundle = bob_store_builder.make_bundle_with_latest_keys(1.into());
|
||||
|
||||
process_prekey_bundle(
|
||||
&bob_address,
|
||||
&mut alice_store.session_store,
|
||||
&mut alice_store.identity_store,
|
||||
&bob_pre_key_bundle,
|
||||
SystemTime::UNIX_EPOCH,
|
||||
&mut csprng,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let initial_session = alice_store
|
||||
.session_store
|
||||
.load_session(&bob_address)
|
||||
.await
|
||||
.expect("session can be loaded")
|
||||
.expect("session exists");
|
||||
assert!(initial_session
|
||||
.has_usable_sender_chain(SystemTime::UNIX_EPOCH)
|
||||
.expect("can check for a sender chain"));
|
||||
assert!(!initial_session
|
||||
.has_usable_sender_chain(SystemTime::UNIX_EPOCH + WELL_PAST_EXPIRATION)
|
||||
.expect("can check for a sender chain"));
|
||||
|
||||
let original_message = "L'homme est condamné à être libre";
|
||||
let outgoing_message = message_encrypt(
|
||||
original_message.as_bytes(),
|
||||
&bob_address,
|
||||
&mut alice_store.session_store,
|
||||
&mut alice_store.identity_store,
|
||||
SystemTime::UNIX_EPOCH + Duration::from_secs(1),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(
|
||||
outgoing_message.message_type(),
|
||||
CiphertextMessageType::PreKey
|
||||
);
|
||||
|
||||
let updated_session = alice_store
|
||||
.session_store
|
||||
.load_session(&bob_address)
|
||||
.await
|
||||
.expect("session can be loaded")
|
||||
.expect("session exists");
|
||||
assert!(updated_session
|
||||
.has_usable_sender_chain(SystemTime::UNIX_EPOCH)
|
||||
.expect("can check for a sender chain"));
|
||||
assert!(!updated_session
|
||||
.has_usable_sender_chain(SystemTime::UNIX_EPOCH + WELL_PAST_EXPIRATION)
|
||||
.expect("can check for a sender chain"));
|
||||
|
||||
let error = message_encrypt(
|
||||
original_message.as_bytes(),
|
||||
&bob_address,
|
||||
&mut alice_store.session_store,
|
||||
&mut alice_store.identity_store,
|
||||
SystemTime::UNIX_EPOCH + WELL_PAST_EXPIRATION,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
matches!(&error, SignalProtocolError::SessionNotFound(addr) if addr == &bob_address),
|
||||
"{:?}",
|
||||
error
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
.now_or_never()
|
||||
.expect("sync")
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
fn run_session_interaction(alice_session: SessionRecord, bob_session: SessionRecord) -> TestResult {
|
||||
async {
|
||||
|
||||
Reference in New Issue
Block a user