diff --git a/services/commtest/src/identity/olm_account_infos.rs b/services/commtest/src/identity/olm_account_infos.rs index 394ac76b1..1207b17ea 100644 --- a/services/commtest/src/identity/olm_account_infos.rs +++ b/services/commtest/src/identity/olm_account_infos.rs @@ -1,84 +1,50 @@ -use lazy_static::lazy_static; use rand::{distributions::Alphanumeric, Rng}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct IdentityPublicKeys { pub ed25519: String, pub curve25519: String, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct ClientPublicKeys { pub primary_identity_public_keys: IdentityPublicKeys, pub notification_identity_public_keys: IdentityPublicKeys, } impl ClientPublicKeys { /// Generates random keys with given `ed25519` primary account /// signing public key. Use [`ClientPublicKeys::default`] for random key. pub fn new(primary_signing_public_key: impl Into) -> Self { Self { primary_identity_public_keys: IdentityPublicKeys { ed25519: primary_signing_public_key.into(), curve25519: generate_random_olm_key(), }, notification_identity_public_keys: IdentityPublicKeys { ed25519: generate_random_olm_key(), curve25519: generate_random_olm_key(), }, } } pub fn device_id(&self) -> &str { &self.primary_identity_public_keys.ed25519 } } impl Default for ClientPublicKeys { fn default() -> Self { Self::new(generate_random_olm_key()) } } -lazy_static! { - pub static ref DEFAULT_CLIENT_KEYS: ClientPublicKeys = ClientPublicKeys { - primary_identity_public_keys: IdentityPublicKeys { - ed25519: "cSlL+VLLJDgtKSPlIwoCZg0h0EmHlQoJC08uV/O+jvg".to_string(), - curve25519: "Y4ZIqzpE1nv83kKGfvFP6rifya0itRg2hifqYtsISnk".to_string(), - }, - notification_identity_public_keys: IdentityPublicKeys { - ed25519: "D0BV2Y7Qm36VUtjwyQTJJWYAycN7aMSJmhEsRJpW2mk".to_string(), - curve25519: "DYmV8VdkjwG/VtC8C53morogNJhpTPT/4jzW0/cxzQo".to_string(), - } - }; - pub static ref MOCK_CLIENT_KEYS_1: ClientPublicKeys = ClientPublicKeys { - primary_identity_public_keys: IdentityPublicKeys { - ed25519: "lbp5cS9fH5NnWIJbZ57wGBzDBGvmjoq6gMBHsIyXfJ4".to_string(), - curve25519: "x74rEeVzfTcjm+B2yLN/wgfvHEzEtphQ/JeQfIrzPzQ".to_string(), - }, - notification_identity_public_keys: IdentityPublicKeys { - ed25519: "+mi3TltiSK2883cm0TK2mkSKPcQb+WVfshltTSVgA2Y".to_string(), - curve25519: "GI8V9FwOYIqxB2TzQN31nXKR8y3/B3k+ZOCgxkTlUlI".to_string(), - }, - }; - pub static ref MOCK_CLIENT_KEYS_2: ClientPublicKeys = ClientPublicKeys { - primary_identity_public_keys: IdentityPublicKeys { - ed25519: "ZXx1ADCFxFm6P+UmVhX0A1tuqUoBU7lYjig/gMzSEJI".to_string(), - curve25519: "zHfP5eeD3slrgidtNRknHw3NKtJ7hA+vinaT3ACIhRA".to_string(), - }, - notification_identity_public_keys: IdentityPublicKeys { - ed25519: "TqzVFQLnJvt9JfMVU54d6InEd/wQV3DCplBuj5axTlU".to_string(), - curve25519: "nRVVaf+Iz2MfEFtQtzrvV/EmTivqKpOeHlCt9OWYUxM".to_string(), - }, - }; -} - pub fn generate_random_olm_key() -> String { rand::thread_rng() .sample_iter(&Alphanumeric) .take(43) .map(char::from) .collect() } diff --git a/services/commtest/tests/identity_device_list_tests.rs b/services/commtest/tests/identity_device_list_tests.rs index 12d86552e..f8d461f22 100644 --- a/services/commtest/tests/identity_device_list_tests.rs +++ b/services/commtest/tests/identity_device_list_tests.rs @@ -1,565 +1,558 @@ use std::collections::{HashMap, HashSet}; use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; use commtest::identity::device::{ login_user_device, logout_user_device, register_user_device, register_user_device_with_device_list, DEVICE_TYPE, PLACEHOLDER_CODE_VERSION, }; +use commtest::identity::olm_account_infos::ClientPublicKeys; use commtest::identity::SigningCapableAccount; use commtest::service_addr; use grpc_clients::identity::authenticated::ChainedInterceptedAuthClient; use grpc_clients::identity::protos::auth::{ PeersDeviceListsRequest, UpdateDeviceListRequest, }; use grpc_clients::identity::protos::authenticated::GetDeviceListRequest; use grpc_clients::identity::DeviceType; use grpc_clients::identity::{get_auth_client, PlatformMetadata}; use serde::{Deserialize, Serialize}; // 1. register user with android device // 2. register a web device // 3. remove android device // 4. register ios device // 5. get device list - should have 4 updates: // - [android] // - [android, web] // - [web] // - [ios, web] - mobile should be first #[tokio::test] async fn test_device_list_rotation() { - use commtest::identity::olm_account_infos::{ - DEFAULT_CLIENT_KEYS as DEVICE_KEYS_ANDROID, - MOCK_CLIENT_KEYS_1 as DEVICE_KEYS_WEB, - MOCK_CLIENT_KEYS_2 as DEVICE_KEYS_IOS, - }; + let device_keys_web = ClientPublicKeys::default(); + let device_keys_ios = ClientPublicKeys::default(); + let device_keys_android = ClientPublicKeys::default(); // Create viewer (user that doesn't change devices) let viewer = register_user_device(None, None).await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), viewer.user_id.clone(), viewer.device_id, viewer.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); - let android_device_id = - &DEVICE_KEYS_ANDROID.primary_identity_public_keys.ed25519; - let web_device_id = &DEVICE_KEYS_WEB.primary_identity_public_keys.ed25519; - let ios_device_id = &DEVICE_KEYS_IOS.primary_identity_public_keys.ed25519; + let android_device_id = device_keys_android.device_id(); + let web_device_id = device_keys_web.device_id(); + let ios_device_id = device_keys_ios.device_id(); // 1. Register user with primary Android device let android = - register_user_device(Some(&DEVICE_KEYS_ANDROID), Some(DeviceType::Android)) + register_user_device(Some(&device_keys_android), Some(DeviceType::Android)) .await; let user_id = android.user_id.clone(); let username = android.username.clone(); // 2. Log in a web device let _web = login_user_device( &username, - Some(&DEVICE_KEYS_WEB), + Some(&device_keys_web), Some(DeviceType::Web), false, ) .await; // 3. Remove android device logout_user_device(android).await; // 4. Log in an iOS device let _ios = login_user_device( &username, - Some(&DEVICE_KEYS_IOS), + Some(&device_keys_ios), Some(DeviceType::Ios), false, ) .await; // Get device list updates for the user let device_lists_response: Vec> = get_raw_device_list_history(&mut auth_client, &user_id) .await .into_iter() .map(|device_list| device_list.devices) .collect(); let expected_device_list: Vec> = vec![ vec![android_device_id.into()], vec![android_device_id.into(), web_device_id.into()], vec![web_device_id.into()], vec![ios_device_id.into(), web_device_id.into()], ]; assert_eq!(device_lists_response, expected_device_list); } #[tokio::test] async fn test_update_device_list_rpc() { // Register user with primary device let primary_device = register_user_device(None, None).await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), primary_device.user_id.clone(), primary_device.device_id, primary_device.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); // Initial device list check let initial_device_list = get_raw_device_list_history(&mut auth_client, &primary_device.user_id) .await .into_iter() .map(|device_list| device_list.devices) .next() .expect("Expected to get single device list update"); assert!(initial_device_list.len() == 1, "Expected single device"); let primary_device_id = initial_device_list[0].clone(); // perform update by adding a new device let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); let devices_payload = vec![primary_device_id, "device2".to_string()]; let update_payload = SignedDeviceList::from_raw_unsigned(&RawDeviceList { devices: devices_payload.clone(), timestamp: now.as_millis() as i64, }); let update_request = UpdateDeviceListRequest::from(&update_payload); auth_client .update_device_list(update_request) .await .expect("Update device list RPC failed"); // get device list again let last_device_list = get_raw_device_list_history(&mut auth_client, &primary_device.user_id) .await; let last_device_list = last_device_list .last() .expect("Failed to get last device list update"); // check that the device list is properly updated assert_eq!(last_device_list.devices, devices_payload); assert_eq!(last_device_list.timestamp, now.as_millis() as i64); } #[tokio::test] async fn test_device_list_signatures() { // device list history as list of tuples: (signature, devices) type DeviceListHistoryItem = (Option, Vec); // Register user with primary device let mut primary_account = SigningCapableAccount::new(); let primary_device_keys = primary_account.public_keys(); let primary_device_id = primary_device_keys.device_id(); let user = register_user_device(Some(&primary_device_keys), Some(DeviceType::Ios)) .await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), user.user_id.clone(), user.device_id, user.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); // Perform unsigned update (add a new device) let first_update: DeviceListHistoryItem = { let update_payload = SignedDeviceList::from_raw_unsigned(&RawDeviceList::new(vec![ primary_device_id.to_string(), "device2".to_string(), ])); let update_request = UpdateDeviceListRequest::from(&update_payload); auth_client .update_device_list(update_request) .await .expect("Unsigned device list update failed"); ( update_payload.cur_primary_signature.clone(), update_payload.into_raw().devices, ) }; // now perform a update (remove a device), but sign the device list let second_update: DeviceListHistoryItem = { let update_payload = SignedDeviceList::create_signed( &RawDeviceList::new(vec![primary_device_id.to_string()]), &mut primary_account, None, ); let update_request = UpdateDeviceListRequest::from(&update_payload); auth_client .update_device_list(update_request) .await .expect("Signed device list update failed"); ( update_payload.cur_primary_signature.clone(), update_payload.into_raw().devices, ) }; // now perform a signed update (add a device), but with invalid signature { let mut update_payload = SignedDeviceList::create_signed( &RawDeviceList::new(vec![ primary_device_id.to_string(), "device3".to_string(), ]), &mut primary_account, None, ); // malfolm signature by replacing first characters update_payload .cur_primary_signature .as_mut() .expect("signature should be present") .replace_range(0..3, "foo"); let update_request = UpdateDeviceListRequest::from(&update_payload); auth_client .update_device_list(update_request) .await .expect_err("RPC should fail for invalid signature"); } // check the history to make sure our updates are correct let device_list_history = get_device_list_history(&mut auth_client, &user.user_id).await; let expected_devices_lists: Vec = vec![ (None, vec![primary_device_id.to_string()]), // auto-generated during registration first_update, second_update, ]; let actual_device_lists: Vec = device_list_history .into_iter() .map(|list| (list.cur_primary_signature.clone(), list.into_raw().devices)) .collect(); assert_eq!(actual_device_lists, expected_devices_lists); } #[tokio::test] async fn test_keyserver_force_login() { - use commtest::identity::olm_account_infos::{ - DEFAULT_CLIENT_KEYS as DEVICE_KEYS_ANDROID, - MOCK_CLIENT_KEYS_1 as DEVICE_KEYS_KEYSERVER_1, - MOCK_CLIENT_KEYS_2 as DEVICE_KEYS_KEYSERVER_2, - }; + let device_keys_android = ClientPublicKeys::default(); + let device_keys_keyserver_1 = ClientPublicKeys::default(); + let device_keys_keyserver_2 = ClientPublicKeys::default(); // Create viewer (user that doesn't change devices) let viewer = register_user_device(None, None).await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), viewer.user_id.clone(), viewer.device_id, viewer.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); - let android_device_id = - &DEVICE_KEYS_ANDROID.primary_identity_public_keys.ed25519; - let keyserver_1_device_id = - &DEVICE_KEYS_KEYSERVER_1.primary_identity_public_keys.ed25519; - let keyserver_2_device_id = - &DEVICE_KEYS_KEYSERVER_2.primary_identity_public_keys.ed25519; + let android_device_id = device_keys_android.device_id(); + let keyserver_1_device_id = device_keys_keyserver_1.device_id(); + let keyserver_2_device_id = device_keys_keyserver_2.device_id(); // 1. Register user with primary Android device let android = - register_user_device(Some(&DEVICE_KEYS_ANDROID), Some(DeviceType::Android)) + register_user_device(Some(&device_keys_android), Some(DeviceType::Android)) .await; let user_id = android.user_id.clone(); let username = android.username.clone(); // 2. Log in on keyserver 1 let _keyserver_1 = login_user_device( &username, - Some(&DEVICE_KEYS_KEYSERVER_1), + Some(&device_keys_keyserver_1), Some(DeviceType::Keyserver), false, ) .await; // 3. Log in on keyserver 2 with force = true let _keyserver_2 = login_user_device( &username, - Some(&DEVICE_KEYS_KEYSERVER_2), + Some(&device_keys_keyserver_2), Some(DeviceType::Keyserver), true, ) .await; // Get device list updates for the user let device_lists_response: Vec> = get_raw_device_list_history(&mut auth_client, &user_id) .await .into_iter() .map(|device_list| device_list.devices) .collect(); let expected_device_list: Vec> = vec![ vec![android_device_id.into()], vec![android_device_id.into(), keyserver_1_device_id.into()], vec![android_device_id.into()], vec![android_device_id.into(), keyserver_2_device_id.into()], ]; assert_eq!(device_lists_response, expected_device_list); } #[tokio::test] async fn test_device_list_multifetch() { // Create viewer (user that only auths request) let viewer = register_user_device(None, None).await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), viewer.user_id.clone(), viewer.device_id, viewer.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); // Register users and prepare expected device lists let mut expected_device_lists = HashMap::new(); for _ in 0..5 { let user = register_user_device(None, None).await; expected_device_lists.insert(user.user_id, vec![user.device_id]); } // Fetch device lists from server let user_ids: Vec<_> = expected_device_lists.keys().cloned().collect(); let request = PeersDeviceListsRequest { user_ids }; let response_device_lists = auth_client .get_device_lists_for_users(request) .await .expect("GetDeviceListsForUser RPC failed") .into_inner() .users_device_lists; // verify if response has the same user IDs as request let expected_user_ids: HashSet = expected_device_lists.keys().cloned().collect(); let response_user_ids: HashSet = response_device_lists.keys().cloned().collect(); let difference: HashSet<_> = expected_user_ids .symmetric_difference(&response_user_ids) .collect(); assert!(difference.is_empty(), "User IDs differ: {:?}", difference); // verify device list for each user for (user_id, expected_devices) in expected_device_lists { let response_payload = response_device_lists.get(&user_id).unwrap(); let returned_devices = SignedDeviceList::from_str(response_payload) .expect("failed to deserialize signed device list") .into_raw() .devices; assert_eq!( returned_devices, expected_devices, "Device list differs for user: {}, Expected {:?}, but got {:?}", user_id, expected_devices, returned_devices ); } } #[tokio::test] async fn test_initial_device_list() { // create signing account let mut primary_account = SigningCapableAccount::new(); let primary_device_keys = primary_account.public_keys(); let primary_device_id = primary_device_keys.device_id().to_string(); // create initial device list let raw_device_list = RawDeviceList::new(vec![primary_device_id]); let signed_list = SignedDeviceList::create_signed( &raw_device_list, &mut primary_account, None, ); // register user with initial list let user = register_user_device_with_device_list( Some(&primary_device_keys), Some(DeviceType::Ios), Some(signed_list.as_json_string()), ) .await; let mut auth_client = get_auth_client( &service_addr::IDENTITY_GRPC.to_string(), user.user_id.clone(), user.device_id, user.access_token, PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), ) .await .expect("Couldn't connect to identity service"); let mut history = get_device_list_history(&mut auth_client, &user.user_id).await; let received_list = history.pop().expect("Received empty device list history"); assert!( history.is_empty(), "Device list history should have no more updates" ); assert_eq!( received_list.cur_primary_signature, signed_list.cur_primary_signature, "Signature mismatch" ); assert!(received_list.last_primary_signature.is_none()); assert_eq!(received_list.into_raw(), raw_device_list); } // See GetDeviceListResponse in identity_authenticated.proto // for details on the response format. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] #[allow(unused)] struct RawDeviceList { devices: Vec, timestamp: i64, } #[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct SignedDeviceList { raw_device_list: String, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] cur_primary_signature: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] last_primary_signature: Option, } impl RawDeviceList { fn new(devices: Vec) -> Self { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); RawDeviceList { devices, timestamp: now.as_millis() as i64, } } fn as_json_string(&self) -> String { serde_json::to_string(self).expect("Failed to serialize RawDeviceList") } } impl SignedDeviceList { fn from_raw_unsigned(raw: &RawDeviceList) -> Self { Self { raw_device_list: raw.as_json_string(), cur_primary_signature: None, last_primary_signature: None, } } fn create_signed( raw: &RawDeviceList, cur_primary_account: &mut SigningCapableAccount, last_primary_account: Option<&mut SigningCapableAccount>, ) -> Self { let raw_device_list = raw.as_json_string(); let cur_primary_signature = cur_primary_account.sign_message(&raw_device_list); let last_primary_signature = last_primary_account .map(|account| account.sign_message(&raw_device_list)); Self { raw_device_list, cur_primary_signature: Some(cur_primary_signature), last_primary_signature, } } fn into_raw(self) -> RawDeviceList { self .raw_device_list .parse() .expect("Failed to parse raw device list") } fn as_json_string(&self) -> String { serde_json::to_string(self).expect("Failed to serialize SignedDeviceList") } } impl FromStr for SignedDeviceList { type Err = serde_json::Error; fn from_str(s: &str) -> Result { serde_json::from_str(s) } } impl FromStr for RawDeviceList { type Err = serde_json::Error; fn from_str(s: &str) -> Result { // The device list payload is sent as an escaped JSON payload. // Escaped double quotes need to be trimmed before attempting to deserialize serde_json::from_str(&s.replace(r#"\""#, r#"""#)) } } impl From<&SignedDeviceList> for UpdateDeviceListRequest { fn from(value: &SignedDeviceList) -> Self { Self { new_device_list: value.as_json_string(), } } } async fn get_device_list_history( client: &mut ChainedInterceptedAuthClient, user_id: &str, ) -> Vec { let request = GetDeviceListRequest { user_id: user_id.to_string(), since_timestamp: None, }; let response = client .get_device_list_for_user(request) .await .expect("Get device list request failed") .into_inner(); response .device_list_updates .into_iter() .map(|update| { SignedDeviceList::from_str(&update) .expect("Failed to parse device list update") }) .collect() } async fn get_raw_device_list_history( client: &mut ChainedInterceptedAuthClient, user_id: &str, ) -> Vec { get_device_list_history(client, user_id) .await .into_iter() .map(|signed| signed.into_raw()) .collect() } diff --git a/services/commtest/tests/tunnelbroker_integration_tests.rs b/services/commtest/tests/tunnelbroker_integration_tests.rs index 67f3b01b8..8e7929a05 100644 --- a/services/commtest/tests/tunnelbroker_integration_tests.rs +++ b/services/commtest/tests/tunnelbroker_integration_tests.rs @@ -1,95 +1,92 @@ mod proto { tonic::include_proto!("tunnelbroker"); } use commtest::identity::device::register_user_device; -use commtest::identity::olm_account_infos::{ - MOCK_CLIENT_KEYS_1, MOCK_CLIENT_KEYS_2, -}; use commtest::service_addr; use commtest::tunnelbroker::socket::{ create_socket, receive_message, send_message, WebSocketMessageToDevice, }; use proto::tunnelbroker_service_client::TunnelbrokerServiceClient; use proto::MessageToDevice; use std::time::Duration; use tokio::time::sleep; use tunnelbroker_messages::RefreshKeyRequest; #[tokio::test] async fn send_refresh_request() { // Create session as a keyserver let device_info = register_user_device(None, None).await; let mut socket = create_socket(&device_info).await.unwrap(); // Send request for keyserver to refresh keys (identity service) let mut tunnelbroker_client = TunnelbrokerServiceClient::connect(service_addr::TUNNELBROKER_GRPC) .await .unwrap(); let refresh_request = RefreshKeyRequest { device_id: device_info.device_id.clone(), number_of_keys: 5, }; let payload = serde_json::to_string(&refresh_request).unwrap(); let request = MessageToDevice { device_id: device_info.device_id.clone(), payload, }; let grpc_message = tonic::Request::new(request); tunnelbroker_client .send_message_to_device(grpc_message) .await .unwrap(); // Have keyserver receive any websocket messages let response = receive_message(&mut socket).await.unwrap(); // Check that message received by keyserver matches what identity server // issued let serialized_response: RefreshKeyRequest = serde_json::from_str(&response).unwrap(); assert_eq!(serialized_response, refresh_request); } #[tokio::test] async fn test_messages_order() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; let messages = vec![ WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "first message".to_string(), }, WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "second message".to_string(), }, WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "third message".to_string(), }, ]; let mut sender_socket = create_socket(&sender).await.unwrap(); for msg in messages.clone() { send_message(&mut sender_socket, msg).await.unwrap(); } // Wait a specified duration to ensure that message had time to persist sleep(Duration::from_millis(100)).await; let mut receiver_socket = create_socket(&receiver).await.unwrap(); for msg in messages { let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(msg.payload, response); } } diff --git a/services/commtest/tests/tunnelbroker_persist_tests.rs b/services/commtest/tests/tunnelbroker_persist_tests.rs index faeec4c92..f6c1affe3 100644 --- a/services/commtest/tests/tunnelbroker_persist_tests.rs +++ b/services/commtest/tests/tunnelbroker_persist_tests.rs @@ -1,83 +1,80 @@ mod proto { tonic::include_proto!("tunnelbroker"); } use commtest::identity::device::register_user_device; -use commtest::identity::olm_account_infos::{ - MOCK_CLIENT_KEYS_1, MOCK_CLIENT_KEYS_2, -}; use commtest::service_addr; use commtest::tunnelbroker::socket::{ create_socket, receive_message, send_message, WebSocketMessageToDevice, }; use proto::tunnelbroker_service_client::TunnelbrokerServiceClient; use proto::MessageToDevice; use std::time::Duration; use tokio::time::sleep; use tunnelbroker_messages::RefreshKeyRequest; /// Tests that a message to an offline device gets pushed to dynamodb /// then recalled once a device connects #[tokio::test] async fn persist_grpc_messages() { let device_info = register_user_device(None, None).await; // Send request for keyserver to refresh keys (identity service) let mut tunnelbroker_client = TunnelbrokerServiceClient::connect(service_addr::TUNNELBROKER_GRPC) .await .unwrap(); let refresh_request = RefreshKeyRequest { device_id: device_info.device_id.to_string(), number_of_keys: 5, }; let payload = serde_json::to_string(&refresh_request).unwrap(); let request = MessageToDevice { device_id: device_info.device_id.to_string(), payload, }; let grpc_message = tonic::Request::new(request); tunnelbroker_client .send_message_to_device(grpc_message) .await .unwrap(); // Wait a specified duration to ensure that message had time to persist sleep(Duration::from_millis(100)).await; let mut socket = create_socket(&device_info).await.unwrap(); // Have keyserver receive any websocket messages let response = receive_message(&mut socket).await.unwrap(); // Check that message received by keyserver matches what identity server // issued let serialized_response: RefreshKeyRequest = serde_json::from_str(&response).unwrap(); assert_eq!(serialized_response, refresh_request); } #[tokio::test] async fn persist_websocket_messages() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; // Send message to not connected client let mut sender_socket = create_socket(&sender).await.unwrap(); let request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "persisted message".to_string(), }; send_message(&mut sender_socket, request.clone()) .await .unwrap(); // Wait a specified duration to ensure that message had time to persist sleep(Duration::from_millis(100)).await; let mut receiver_socket = create_socket(&receiver).await.unwrap(); let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(request.payload, response); } diff --git a/services/commtest/tests/tunnelbroker_recipient_confirmation_tests.rs b/services/commtest/tests/tunnelbroker_recipient_confirmation_tests.rs index 46be4c008..2429f32b2 100644 --- a/services/commtest/tests/tunnelbroker_recipient_confirmation_tests.rs +++ b/services/commtest/tests/tunnelbroker_recipient_confirmation_tests.rs @@ -1,197 +1,194 @@ use commtest::identity::device::register_user_device; -use commtest::identity::olm_account_infos::{ - MOCK_CLIENT_KEYS_1, MOCK_CLIENT_KEYS_2, -}; use commtest::tunnelbroker::socket::{ create_socket, receive_message, send_message, WebSocketMessageToDevice, }; use futures_util::{SinkExt, StreamExt}; use std::time::Duration; use tokio::time::sleep; use tokio_tungstenite::tungstenite::Message; use tokio_tungstenite::tungstenite::Message::Close; use tunnelbroker_messages::MessageToDevice; #[tokio::test] async fn deliver_until_confirmation_not_connected() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; // send message to not connected client let mut sender_socket = create_socket(&sender).await.unwrap(); let request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "message from deliver_until_confirmation_not_connected" .to_string(), }; send_message(&mut sender_socket, request.clone()) .await .unwrap(); // wait a specified duration to ensure that message had time to persist sleep(Duration::from_millis(100)).await; let mut receiver_socket = create_socket(&receiver).await.unwrap(); // receive message for the first time (without confirmation) let Some(Ok(response)) = receiver_socket.next().await else { panic!("Receiving first message failed") }; let message = response.to_text().unwrap(); let message_to_device = serde_json::from_str::(message).unwrap(); assert_eq!(request.payload, message_to_device.payload); // restart connection receiver_socket .send(Close(None)) .await .expect("Failed to send message"); receiver_socket = create_socket(&receiver).await.unwrap(); // receive message for the second time let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(request.payload, response); } #[tokio::test] async fn deliver_until_confirmation_connected() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; // send message to connected client let mut receiver_socket = create_socket(&receiver).await.unwrap(); let mut sender_socket = create_socket(&sender).await.unwrap(); let request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "message from deliver_until_confirmation_connected".to_string(), }; send_message(&mut sender_socket, request.clone()) .await .unwrap(); // receive message for the first time (without confirmation) let Some(Ok(response)) = receiver_socket.next().await else { panic!("Receiving first message failed") }; let message = response.to_text().unwrap(); let message_to_device = serde_json::from_str::(message).unwrap(); assert_eq!(request.payload, message_to_device.payload); // restart connection receiver_socket .send(Close(None)) .await .expect("Failed to send message"); receiver_socket = create_socket(&receiver).await.unwrap(); // receive message for the second time let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(request.payload, response); } #[tokio::test] async fn test_confirming_deleted_message() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; // send message to connected client let mut receiver_socket = create_socket(&receiver).await.unwrap(); let mut sender_socket = create_socket(&sender).await.unwrap(); let request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "message to bo confirmed twice".to_string(), }; send_message(&mut sender_socket, request.clone()) .await .unwrap(); // receive a message let Some(Ok(response)) = receiver_socket.next().await else { panic!("Receiving first message failed") }; let message = response.to_text().unwrap(); let message_to_device = serde_json::from_str::(message).unwrap(); assert_eq!(request.payload, message_to_device.payload); let confirmation = tunnelbroker_messages::MessageReceiveConfirmation { message_ids: vec![message_to_device.message_id], }; let serialized_confirmation = serde_json::to_string(&confirmation).unwrap(); // send confirmation twice receiver_socket .send(Message::Text(serialized_confirmation.clone())) .await .expect("Error while sending confirmation"); receiver_socket .send(Message::Text(serialized_confirmation)) .await .expect("Error while sending confirmation"); // test if socket is still alive by sending and receiving a message let second_request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "second request".to_string(), }; send_message(&mut sender_socket, second_request.clone()) .await .unwrap(); let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(second_request.payload, response); } #[tokio::test] async fn test_confirming() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; // send message to connected client let mut receiver_socket = create_socket(&receiver).await.unwrap(); let mut sender_socket = create_socket(&sender).await.unwrap(); // send first message let first_request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "first request".to_string(), }; send_message(&mut sender_socket, first_request.clone()) .await .unwrap(); // receive a first message let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(first_request.payload, response); // restart connection receiver_socket .send(Close(None)) .await .expect("Failed to send message"); tokio::time::sleep(Duration::from_millis(200)).await; receiver_socket = create_socket(&receiver).await.unwrap(); // send second message let second_request = WebSocketMessageToDevice { device_id: receiver.device_id.clone(), payload: "second request".to_string(), }; send_message(&mut sender_socket, second_request.clone()) .await .unwrap(); // make sure only second message is received let response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(second_request.payload, response) } diff --git a/services/commtest/tests/tunnelbroker_sender_confirmation_tests.rs b/services/commtest/tests/tunnelbroker_sender_confirmation_tests.rs index 23f0f3ada..26e29cd18 100644 --- a/services/commtest/tests/tunnelbroker_sender_confirmation_tests.rs +++ b/services/commtest/tests/tunnelbroker_sender_confirmation_tests.rs @@ -1,93 +1,90 @@ use commtest::identity::device::register_user_device; -use commtest::identity::olm_account_infos::{ - DEFAULT_CLIENT_KEYS, MOCK_CLIENT_KEYS_1, MOCK_CLIENT_KEYS_2, -}; use commtest::tunnelbroker::socket::{create_socket, receive_message}; use futures_util::{SinkExt, StreamExt}; use tokio_tungstenite::tungstenite::Message; use tunnelbroker_messages::{ MessageSentStatus, MessageToDeviceRequest, MessageToDeviceRequestStatus, }; /// Tests of responses sent from Tunnelberoker to client /// trying to send message to other device #[tokio::test] async fn get_confirmation() { - let sender = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; - let receiver = register_user_device(Some(&MOCK_CLIENT_KEYS_2), None).await; + let sender = register_user_device(None, None).await; + let receiver = register_user_device(None, None).await; let client_message_id = "mockID".to_string(); // Send message to not connected client let payload = "persisted message"; let request = MessageToDeviceRequest { client_message_id: client_message_id.clone(), device_id: receiver.device_id.clone(), payload: payload.to_string(), }; let serialized_request = serde_json::to_string(&request) .expect("Failed to serialize message to device"); let mut sender_socket = create_socket(&sender).await.unwrap(); sender_socket .send(Message::Text(serialized_request)) .await .expect("Failed to send message"); if let Some(Ok(response)) = sender_socket.next().await { let expected_response = MessageToDeviceRequestStatus { client_message_ids: vec![MessageSentStatus::Success(client_message_id)], }; let expected_payload = serde_json::to_string(&expected_response).unwrap(); let received_payload = response.to_text().unwrap(); assert_eq!(received_payload, expected_payload); }; // Connect receiver to flush DDB and avoid polluting other tests let mut receiver_socket = create_socket(&receiver).await.unwrap(); let receiver_response = receive_message(&mut receiver_socket).await.unwrap(); assert_eq!(payload, receiver_response); } #[tokio::test] async fn get_serialization_error() { - let sender = register_user_device(Some(&DEFAULT_CLIENT_KEYS), None).await; + let sender = register_user_device(None, None).await; let message = "some bad json".to_string(); let mut sender_socket = create_socket(&sender).await.unwrap(); sender_socket .send(Message::Text(message.clone())) .await .expect("Failed to send message"); if let Some(Ok(response)) = sender_socket.next().await { let expected_response = MessageToDeviceRequestStatus { client_message_ids: vec![MessageSentStatus::SerializationError(message)], }; let expected_payload = serde_json::to_string(&expected_response).unwrap(); let received_payload = response.to_text().unwrap(); assert_eq!(received_payload, expected_payload); }; } #[tokio::test] async fn get_invalid_request_error() { - let sender = register_user_device(Some(&DEFAULT_CLIENT_KEYS), None).await; + let sender = register_user_device(None, None).await; let mut sender_socket = create_socket(&sender).await.unwrap(); sender_socket .send(Message::Binary(vec![])) .await .expect("Failed to send message"); if let Some(Ok(response)) = sender_socket.next().await { let expected_response = MessageToDeviceRequestStatus { client_message_ids: vec![MessageSentStatus::InvalidRequest], }; let expected_payload = serde_json::to_string(&expected_response).unwrap(); let received_payload = response.to_text().unwrap(); assert_eq!(received_payload, expected_payload); }; } diff --git a/services/commtest/tests/tunnelbroker_websocket_messages_tests.rs b/services/commtest/tests/tunnelbroker_websocket_messages_tests.rs index 38452c417..c3daedccb 100644 --- a/services/commtest/tests/tunnelbroker_websocket_messages_tests.rs +++ b/services/commtest/tests/tunnelbroker_websocket_messages_tests.rs @@ -1,49 +1,48 @@ use commtest::identity::device::register_user_device; -use commtest::identity::olm_account_infos::MOCK_CLIENT_KEYS_1; use commtest::tunnelbroker::socket::create_socket; use futures_util::{SinkExt, StreamExt}; use tokio_tungstenite::tungstenite::{Error, Message, Message::Close}; /// Tests for message types defined in tungstenite crate #[tokio::test] async fn test_ping_pong() { - let device = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; + let device = register_user_device(None, None).await; let ping_message = vec![1, 2, 3, 4, 5]; let mut socket = create_socket(&device).await.unwrap(); socket .send(Message::Ping(ping_message.clone())) .await .expect("Failed to send message"); if let Some(Ok(response)) = socket.next().await { let received_payload = match response { Message::Pong(received_payload) => received_payload, unexpected => panic!( "Unexpected message type or result. Expected Pong, got: {:?}. ", unexpected ), }; assert_eq!(ping_message.clone(), received_payload); }; } #[tokio::test] async fn test_close_message() { - let device = register_user_device(Some(&MOCK_CLIENT_KEYS_1), None).await; + let device = register_user_device(None, None).await; let mut socket = create_socket(&device).await.unwrap(); socket .send(Close(None)) .await .expect("Failed to send message"); if let Some(response) = socket.next().await { assert!(matches!( response, Err(Error::AlreadyClosed | Error::ConnectionClosed) | Ok(Close(None)) )); }; }