use common_api::crypto::prelude::*; use near_primitives_core::{account::id::AccountId, types::Balance}; use near_primitives_light::types::Finality; use near_rpc::client::{NearClient, Signer}; use rand::{RngCore, SeedableRng}; use rand_chacha::ChaChaRng; use serde::{Deserialize, Serialize}; use std::str::FromStr; use url::Url; use wasm_bindgen::JsValue; use wasm_bindgen_futures::JsFuture; use wasm_bindgen_test::*; use web_client::{KeyProvisioner, ProvisionerConfig}; wasm_bindgen_test_configure!(run_in_browser); #[derive(Serialize, Deserialize)] struct ValidatorKey { account_id: AccountId, public_key: Ed25519PublicKey, secret_key: String, } fn random_bits() -> [u8; 32] { let mut chacha = ChaChaRng::from_entropy(); let mut secret_bytes = [0_u8; 32]; chacha.fill_bytes(&mut secret_bytes); secret_bytes } async fn create_account( client: &NearClient, validator: &Signer, account_id_str: &str, amount: Balance, ) -> anyhow::Result { let id = AccountId::from_str(account_id_str)?; let sk = Ed25519SecretKey::try_from_bytes(&random_bits())?; let pk = Ed25519PublicKey::from(&sk); client .create_account(validator, &id, pk, amount) .commit(Finality::Final) .await?; let nonce = Result::from( client .view_access_key(&id, &pk, Finality::None) .await .unwrap(), ) .map_err(|err| anyhow::anyhow!(err))?; Ok(Signer::from_secret(sk, id, nonce)) } async fn delete_account( client: &NearClient, signer: &Signer, beneficiary_acc_id: &AccountId, ) -> anyhow::Result<()> { let id = signer.account().clone(); let pk = signer.public_key(); let nonce = Result::from(client.view_access_key(&id, pk, Finality::Final).await?) .map_err(|err| anyhow::anyhow!(err))?; signer.update_nonce(nonce); client .delete_account(signer, &id, beneficiary_acc_id) .commit(Finality::Final) .await?; Ok(()) } async fn validator_key() -> anyhow::Result { Ok( reqwest::get("http://sandbox-artifact:3032/validator_key.json") .await? .json::() .await?, ) } async fn validator_account( client: &NearClient, validator_key: ValidatorKey, ) -> anyhow::Result { let key_nonce = Result::from( client .view_access_key( &validator_key.account_id, &validator_key.public_key, Finality::Final, ) .await?, ) .map_err(|err| anyhow::anyhow!(err))?; let signer = Signer::from_secret_str( &validator_key.secret_key, validator_key.account_id.clone(), key_nonce, )?; Ok(signer) } async fn meeting_room_contract() -> anyhow::Result> { Ok( reqwest::get("http://contract-artifact:3033/meeting_room.wasm") .await? .bytes() .await? .to_vec(), ) } #[wasm_bindgen_test] async fn pass() { console_log!("Test Passed"); } #[wasm_bindgen_test] async fn key_exchange() { let rpc_url = Url::parse("http://sandbox:3030").unwrap(); let client = NearClient::new(rpc_url).unwrap(); let validator_key = validator_key().await.unwrap(); let validator = validator_account(&client, validator_key).await.unwrap(); // create account for key-exchange // Alice is an initiator account let alice_sg = create_account( &client, &validator, "alice.test.near", near_units::near::parse("10 N").unwrap(), ) .await .unwrap(); let bob_sg = create_account( &client, &validator, "bob.test.near", near_units::near::parse("10 N").unwrap(), ) .await .unwrap(); let karl_sg = create_account( &client, &validator, "karl.test.near", near_units::near::parse("10 N").unwrap(), ) .await .unwrap(); let mike_sg = create_account( &client, &validator, "mike.test.near", near_units::near::parse("10 N").unwrap(), ) .await .unwrap(); // Create an contract account let contract_sg = create_account( &client, &validator, "contract.test.near", near_units::near::parse("200 N").unwrap(), ) .await .unwrap(); // Contract byte code let contract_wasm = meeting_room_contract().await.unwrap(); let contract_id = contract_sg.account().clone(); client .deploy_contract(&contract_sg, &contract_id, contract_wasm) .commit(Finality::Final) .await .unwrap(); // config with endpoints let config = ProvisionerConfig::new( contract_id.to_string(), "http://sandbox:3030", "http://key-exchange:3000", ) .unwrap(); // Create provisioners for each user let keypair_str = alice_sg.secret_key().string(); let provisioner = KeyProvisioner::new( keypair_str, alice_sg.nonce(), alice_sg.account().to_string(), config.clone(), ) .unwrap(); let arr = JsValue::from( &[ bob_sg.account().to_string(), karl_sg.account().to_string(), mike_sg.account().to_string(), ] .into_iter() .map(|it| JsValue::from_str(&it)) .collect::(), ); let set = js_sys::Set::new(&arr); // Init meeting let meeting_id = JsFuture::from(provisioner.init(set, 3000)) .await .unwrap() .as_string() .unwrap(); // Then each user push own key to blockchain let keypair_str = bob_sg.secret_key().string(); let provisioner_bob = KeyProvisioner::new( keypair_str, bob_sg.nonce(), bob_sg.account().to_string(), config.clone(), ) .unwrap(); let _ = JsFuture::from(provisioner_bob.push_to_near(meeting_id.clone(), 3000)) .await .unwrap(); let keypair_str = karl_sg.secret_key().string(); let provisioner_karl = KeyProvisioner::new( keypair_str, karl_sg.nonce(), karl_sg.account().to_string(), config.clone(), ) .unwrap(); let _ = JsFuture::from(provisioner_karl.push_to_near(meeting_id.clone(), 3000)) .await .unwrap(); let keypair_str = mike_sg.secret_key().string(); let provisioner_mike = KeyProvisioner::new( keypair_str, mike_sg.nonce(), mike_sg.account().to_string(), config.clone(), ) .unwrap(); let _ = JsFuture::from(provisioner_mike.push_to_near(meeting_id.clone(), 3000)) .await .unwrap(); // Send encrypted keys to participants // timeout in millis let alice_key = JsFuture::from(provisioner.send_keys(meeting_id.clone(), 200)) .await .unwrap() .as_string() .unwrap(); // Fetch encrypted keys let bob_key = JsFuture::from(provisioner_bob.get_key(meeting_id.clone(), 200)) .await .unwrap() .as_string() .unwrap(); let karl_key = JsFuture::from(provisioner_karl.get_key(meeting_id.clone(), 200)) .await .unwrap() .as_string() .unwrap(); let mike_key = JsFuture::from(provisioner_mike.get_key(meeting_id.clone(), 200)) .await .unwrap() .as_string() .unwrap(); assert!(&[mike_key, bob_key, karl_key] .into_iter() .all(|key| key == alice_key)); // delete all accounts delete_account(&client, &contract_sg, validator.account()) .await .unwrap(); delete_account(&client, &alice_sg, validator.account()) .await .unwrap(); delete_account(&client, &bob_sg, validator.account()) .await .unwrap(); delete_account(&client, &karl_sg, validator.account()) .await .unwrap(); delete_account(&client, &mike_sg, validator.account()) .await .unwrap(); } #[wasm_bindgen_test] async fn sandbox() {}