diff --git a/services/commtest/src/identity/device.rs b/services/commtest/src/identity/device.rs index 20e29abb4..122581a4c 100644 --- a/services/commtest/src/identity/device.rs +++ b/services/commtest/src/identity/device.rs @@ -1,93 +1,98 @@ use comm_opaque2::client::Registration; use rand::{distributions::Alphanumeric, Rng}; mod proto { tonic::include_proto!("identity.client"); } +use crate::identity::olm_account_infos::{ + ClientPublicKeys, DEFAULT_CLIENT_KEYS, +}; use proto as client; use proto::{ identity_client_service_client::IdentityClientServiceClient, DeviceKeyUpload, IdentityKeyInfo, PreKey, RegistrationFinishRequest, RegistrationStartRequest, }; pub struct DeviceInfo { pub username: String, pub user_id: String, pub device_id: String, pub access_token: String, } -pub async fn create_device() -> DeviceInfo { +pub async fn create_device(keys: Option<&ClientPublicKeys>) -> DeviceInfo { let password = "pass"; let username: String = rand::thread_rng() .sample_iter(&Alphanumeric) .take(7) .map(char::from) .collect(); // TODO: Generate dynamic valid olm account info - let example_payload = r#"{\"notificationIdentityPublicKeys\":{\"curve25519\":\"DYmV8VdkjwG/VtC8C53morogNJhpTPT/4jzW0/cxzQo\",\"ed25519\":\"D0BV2Y7Qm36VUtjwyQTJJWYAycN7aMSJmhEsRJpW2mk\"},\"primaryIdentityPublicKeys\":{\"curve25519\":\"Y4ZIqzpE1nv83kKGfvFP6rifya0itRg2hifqYtsISnk\",\"ed25519\":\"cSlL+VLLJDgtKSPlIwoCZg0h0EmHlQoJC08uV/O+jvg\"}}"#; + let keys = keys.unwrap_or_else(|| &DEFAULT_CLIENT_KEYS); + let example_payload = + serde_json::to_string(&keys).expect("Failed to serialize example payload"); // The ed25519 value from the olm payload - let device_id = r#"cSlL+VLLJDgtKSPlIwoCZg0h0EmHlQoJC08uV/O+jvg"#; + let device_id = &keys.primary_identity_public_keys.ed25519; let mut client_registration = Registration::new(); let opaque_registration_request = client_registration.start(password).unwrap(); let registration_start_request = RegistrationStartRequest { opaque_registration_request, username: username.to_string(), device_key_upload: Some(DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: example_payload.to_string(), payload_signature: "foo".to_string(), social_proof: None, }), content_upload: Some(PreKey { pre_key: "content_prekey".to_string(), pre_key_signature: "content_prekey_sig".to_string(), }), notif_upload: Some(PreKey { pre_key: "notif_prekey".to_string(), pre_key_signature: "notif_prekey_sig".to_string(), }), one_time_content_prekeys: Vec::new(), one_time_notif_prekeys: Vec::new(), device_type: client::DeviceType::Keyserver.into(), }), }; // TODO: allow endpoint to be configured let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identitiy service"); let registration_start_response = identity_client .register_password_user_start(registration_start_request) .await .unwrap() .into_inner(); let opaque_registration_upload = client_registration .finish( password, ®istration_start_response.opaque_registration_response, ) .unwrap(); let registration_finish_request = RegistrationFinishRequest { session_id: registration_start_response.session_id, opaque_registration_upload, }; let registration_finish_response = identity_client .register_password_user_finish(registration_finish_request) .await .unwrap() .into_inner(); DeviceInfo { username: username.to_string(), device_id: device_id.to_string(), user_id: registration_finish_response.user_id, access_token: registration_finish_response.access_token, } } diff --git a/services/commtest/src/identity/mod.rs b/services/commtest/src/identity/mod.rs index 545892414..2563814b2 100644 --- a/services/commtest/src/identity/mod.rs +++ b/services/commtest/src/identity/mod.rs @@ -1 +1,2 @@ pub mod device; +pub mod olm_account_infos; diff --git a/services/commtest/src/identity/olm_account_infos.rs b/services/commtest/src/identity/olm_account_infos.rs new file mode 100644 index 000000000..c233e2739 --- /dev/null +++ b/services/commtest/src/identity/olm_account_infos.rs @@ -0,0 +1,48 @@ +use lazy_static::lazy_static; +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, +} + +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(), + }, + }; +} diff --git a/services/commtest/tests/grpc_client_test.rs b/services/commtest/tests/grpc_client_test.rs index d73f20872..4bd0d8322 100644 --- a/services/commtest/tests/grpc_client_test.rs +++ b/services/commtest/tests/grpc_client_test.rs @@ -1,30 +1,30 @@ use commtest::identity::device::create_device; #[tokio::test] async fn verify_access_token() { use grpc_clients::identity::unauthenticated::client::verify_user_access_token; - let device_info = create_device().await; + let device_info = create_device(None).await; let token_valid = verify_user_access_token( "http://127.0.0.1:50054", &device_info.user_id, &device_info.device_id, &device_info.access_token, ) .await .expect("Failed to call identity's verify_user_access_token endpoint"); assert_eq!(token_valid, true); // Try again with invalid access token let token_valid = verify_user_access_token( "http://127.0.0.1:50054", &device_info.user_id, &device_info.device_id, "garbage", ) .await .expect("Failed to call identity's verify_user_access_token endpoint"); assert_eq!(token_valid, false); } diff --git a/services/commtest/tests/identity_access_tokens_tests.rs b/services/commtest/tests/identity_access_tokens_tests.rs index ca64f6f38..14a9deca4 100644 --- a/services/commtest/tests/identity_access_tokens_tests.rs +++ b/services/commtest/tests/identity_access_tokens_tests.rs @@ -1,57 +1,57 @@ mod proto { tonic::include_proto!("identity.client"); } use proto as client; mod auth_proto { tonic::include_proto!("identity.authenticated"); } use commtest::identity::device::create_device; use proto::identity_client_service_client::IdentityClientServiceClient; use proto::{UploadOneTimeKeysRequest, VerifyUserAccessTokenRequest}; #[tokio::test] async fn verify_access_token() { - let device_info = create_device().await; + let device_info = create_device(None).await; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identitiy service"); let verify_request = VerifyUserAccessTokenRequest { user_id: device_info.user_id, signing_public_key: device_info.device_id, access_token: device_info.access_token, }; let response = identity_client .verify_user_access_token(verify_request) .await .unwrap(); assert_eq!(response.into_inner().token_valid, true); } #[tokio::test] async fn upload_one_time_keys() { - let device_info = create_device().await; + let device_info = create_device(None).await; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identitiy service"); let upload_request = UploadOneTimeKeysRequest { user_id: device_info.user_id, device_id: device_info.device_id, access_token: device_info.access_token, content_one_time_pre_keys: vec!["a".to_string(), "b".to_string()], notif_one_time_pre_keys: vec!["c".to_string(), "d".to_string()], }; // This send will fail if the one-time keys weren't successfully added identity_client .upload_one_time_keys(upload_request) .await .unwrap(); } diff --git a/services/commtest/tests/identity_keyserver_tests.rs b/services/commtest/tests/identity_keyserver_tests.rs index 5e3ec5167..47b647d51 100644 --- a/services/commtest/tests/identity_keyserver_tests.rs +++ b/services/commtest/tests/identity_keyserver_tests.rs @@ -1,85 +1,85 @@ mod proto { tonic::include_proto!("identity.client"); } use proto as client; mod auth_proto { tonic::include_proto!("identity.authenticated"); } use auth_proto::identity_client_service_client::IdentityClientServiceClient as AuthClient; use auth_proto::OutboundKeysForUserRequest; use client::UploadOneTimeKeysRequest; use commtest::identity::device::create_device; use tonic::{transport::Endpoint, Request}; #[tokio::test] async fn set_prekey() { - let device_info = create_device().await; + let device_info = create_device(None).await; let channel = Endpoint::from_static("http://[::1]:50054") .connect() .await .unwrap(); let mut client = AuthClient::with_interceptor(channel, |mut request: Request<()>| { let metadata = request.metadata_mut(); metadata.insert("user_id", device_info.user_id.parse().unwrap()); metadata.insert("device_id", device_info.device_id.parse().unwrap()); metadata .insert("access_token", device_info.access_token.parse().unwrap()); Ok(request) }); let upload_request = UploadOneTimeKeysRequest { user_id: device_info.user_id.to_string(), device_id: device_info.device_id.to_string(), access_token: device_info.access_token.to_string(), content_one_time_pre_keys: vec!["content1".to_string()], notif_one_time_pre_keys: vec!["notif1".to_string()], }; let mut unauthenticated_client = proto::identity_client_service_client::IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identitiy service"); unauthenticated_client .upload_one_time_keys(upload_request) .await .expect("Failed to upload keys"); // Currently allowed to request your own outbound keys let keyserver_request = OutboundKeysForUserRequest { user_id: device_info.user_id.clone(), }; println!("Getting keyserver info for user, {}", device_info.user_id); let first_reponse = client .get_keyserver_keys(keyserver_request.clone()) .await .expect("Second keyserver keys request failed") .into_inner() .keyserver_info .unwrap(); assert_eq!( first_reponse.one_time_content_prekey, Some("content1".to_string()) ); assert_eq!( first_reponse.one_time_notif_prekey, Some("notif1".to_string()) ); let second_reponse = client .get_keyserver_keys(keyserver_request) .await .expect("Second keyserver keys request failed") .into_inner() .keyserver_info .unwrap(); // The one time keys should be exhausted assert_eq!(second_reponse.one_time_content_prekey, None); assert_eq!(second_reponse.one_time_notif_prekey, None); } diff --git a/services/commtest/tests/identity_one_time_key_tests.rs b/services/commtest/tests/identity_one_time_key_tests.rs index c4171ce64..54933449d 100644 --- a/services/commtest/tests/identity_one_time_key_tests.rs +++ b/services/commtest/tests/identity_one_time_key_tests.rs @@ -1,35 +1,35 @@ mod client { tonic::include_proto!("identity.client"); } mod auth_proto { tonic::include_proto!("identity.authenticated"); } use client::identity_client_service_client::IdentityClientServiceClient; use client::UploadOneTimeKeysRequest; use commtest::identity::device::create_device; #[tokio::test] async fn verify_access_token() { - let device_info = create_device().await; + let device_info = create_device(None).await; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identity service"); let upload_request = UploadOneTimeKeysRequest { user_id: device_info.user_id, device_id: device_info.device_id, access_token: device_info.access_token, content_one_time_pre_keys: vec![ "content1".to_string(), "content2".to_string(), ], notif_one_time_pre_keys: vec!["notif1".to_string(), "notif2".to_string()], }; identity_client .upload_one_time_keys(upload_request) .await .unwrap(); } diff --git a/services/commtest/tests/identity_prekey_tests.rs b/services/commtest/tests/identity_prekey_tests.rs index 9a3497896..1e2560748 100644 --- a/services/commtest/tests/identity_prekey_tests.rs +++ b/services/commtest/tests/identity_prekey_tests.rs @@ -1,49 +1,49 @@ mod proto { tonic::include_proto!("identity.client"); } use proto as client; mod auth_proto { tonic::include_proto!("identity.authenticated"); } use auth_proto::identity_client_service_client::IdentityClientServiceClient as AuthClient; use auth_proto::RefreshUserPreKeysRequest; use client::PreKey; use commtest::identity::device::create_device; use tonic::{transport::Endpoint, Request}; #[tokio::test] async fn set_prekey() { - let device_info = create_device().await; + let device_info = create_device(None).await; let channel = Endpoint::from_static("http://[::1]:50054") .connect() .await .unwrap(); let mut client = AuthClient::with_interceptor(channel, |mut request: Request<()>| { let metadata = request.metadata_mut(); metadata.append("user_id", device_info.user_id.parse().unwrap()); metadata.append("device_id", device_info.device_id.parse().unwrap()); metadata .append("access_token", device_info.access_token.parse().unwrap()); Ok(request) }); let upload_request = RefreshUserPreKeysRequest { new_content_pre_keys: Some(PreKey { pre_key: "content_prekey".to_string(), pre_key_signature: "content_prekey_signature".to_string(), }), new_notif_pre_keys: Some(PreKey { pre_key: "content_prekey".to_string(), pre_key_signature: "content_prekey_signature".to_string(), }), }; // This send will fail if the one-time keys weren't successfully added println!( "Error: {:?}", client.refresh_user_pre_keys(upload_request).await ); } diff --git a/services/commtest/tests/identity_tunnelbroker_tests.rs b/services/commtest/tests/identity_tunnelbroker_tests.rs index 3a05ae329..b96f879ca 100644 --- a/services/commtest/tests/identity_tunnelbroker_tests.rs +++ b/services/commtest/tests/identity_tunnelbroker_tests.rs @@ -1,114 +1,114 @@ mod client { tonic::include_proto!("identity.client"); } mod auth_proto { tonic::include_proto!("identity.authenticated"); } use auth_proto::identity_client_service_client::IdentityClientServiceClient as AuthClient; use client::identity_client_service_client::IdentityClientServiceClient; use client::UploadOneTimeKeysRequest; use commtest::identity::device::create_device; use commtest::tunnelbroker::socket::create_socket; use futures_util::StreamExt; use tonic::transport::Endpoint; use tonic::Request; use tunnelbroker_messages::RefreshKeyRequest; #[tokio::test] #[should_panic] async fn test_tunnelbroker_invalid_auth() { - let mut device_info = create_device().await; + let mut device_info = create_device(None).await; device_info.access_token = "".to_string(); let mut socket = create_socket(&device_info).await; socket .next() .await .expect("Failed to receive response") .expect("Failed to read the response"); } #[tokio::test] async fn test_tunnelbroker_valid_auth() { - let device_info = create_device().await; + let device_info = create_device(None).await; let mut socket = create_socket(&device_info).await; socket .next() .await .expect("Failed to receive response") .expect("Failed to read the response"); } #[tokio::test] async fn test_refresh_keys_request_upon_depletion() { - let device_info = create_device().await; + let device_info = create_device(None).await; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054") .await .expect("Couldn't connect to identitiy service"); let upload_request = UploadOneTimeKeysRequest { user_id: device_info.user_id.clone(), device_id: device_info.device_id.clone(), access_token: device_info.access_token.clone(), content_one_time_pre_keys: vec!["content1".to_string()], notif_one_time_pre_keys: vec!["notif1".to_string()], }; identity_client .upload_one_time_keys(upload_request) .await .unwrap(); // Request outbound keys, which should trigger identity service to ask for more keys let channel = Endpoint::from_static("http://[::1]:50054") .connect() .await .unwrap(); let mut client = AuthClient::with_interceptor(channel, |mut inter_request: Request<()>| { let metadata = inter_request.metadata_mut(); metadata.insert("user_id", device_info.user_id.parse().unwrap()); metadata.insert("device_id", device_info.device_id.parse().unwrap()); metadata .insert("access_token", device_info.access_token.parse().unwrap()); Ok(inter_request) }); let keyserver_request = auth_proto::OutboundKeysForUserRequest { user_id: device_info.user_id.clone(), }; println!("Getting keyserver info for user, {}", device_info.user_id); let _first_reponse = client .get_keyserver_keys(keyserver_request.clone()) .await .expect("Second keyserver keys request failed") .into_inner() .keyserver_info .unwrap(); // The current threshold is 5, but we only upload two. Should receive request // from Tunnelbroker to refresh keys // Create session as a keyserver - let device_info = create_device().await; + let device_info = create_device(None).await; let mut socket = create_socket(&device_info).await; // Have keyserver receive any websocket messages if let Some(Ok(response)) = socket.next().await { // Check that message received by keyserver matches what identity server // issued let serialized_response: RefreshKeyRequest = serde_json::from_str(&response.to_text().unwrap()).unwrap(); let expected_response = RefreshKeyRequest { device_id: device_info.device_id.to_string(), number_of_keys: 5, }; assert_eq!(serialized_response, expected_response); }; } diff --git a/services/commtest/tests/tunnelbroker_integration_tests.rs b/services/commtest/tests/tunnelbroker_integration_tests.rs index 766b67f56..45a0f2446 100644 --- a/services/commtest/tests/tunnelbroker_integration_tests.rs +++ b/services/commtest/tests/tunnelbroker_integration_tests.rs @@ -1,92 +1,92 @@ mod proto { tonic::include_proto!("tunnelbroker"); } use commtest::identity::device::create_device; use commtest::tunnelbroker::socket::create_socket; use futures_util::StreamExt; use proto::tunnelbroker_service_client::TunnelbrokerServiceClient; use proto::MessageToDevice; use tunnelbroker_messages::RefreshKeyRequest; #[tokio::test] async fn send_refresh_request() { // Create session as a keyserver - let device_info = create_device().await; + let device_info = create_device(None).await; let mut socket = create_socket(&device_info).await; // Send request for keyserver to refresh keys (identity service) let mut tunnelbroker_client = TunnelbrokerServiceClient::connect("http://localhost:50051") .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 = socket.next().await.unwrap().unwrap(); // Check that message received by keyserver matches what identity server // issued let serialized_response: RefreshKeyRequest = serde_json::from_str(&response.to_text().unwrap()).unwrap(); assert_eq!(serialized_response, refresh_request); } /// Test that a message to an offline device gets pushed to dynamodb /// then recalled once a device connects #[tokio::test] async fn persist_messages() { - let device_info = create_device().await; + let device_info = create_device(None).await; // Send request for keyserver to refresh keys (identity service) let mut tunnelbroker_client = TunnelbrokerServiceClient::connect("http://localhost:50051") .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 one second to ensure that message had time to persist use std::{thread, time}; let ten_millis = time::Duration::from_millis(50); thread::sleep(ten_millis); let mut socket = create_socket(&device_info).await; // Have keyserver receive any websocket messages if let Some(Ok(response)) = socket.next().await { // Check that message received by keyserver matches what identity server // issued let serialized_response: RefreshKeyRequest = serde_json::from_str(&response.to_text().unwrap()).unwrap(); assert_eq!(serialized_response, refresh_request); }; }