diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e3aa5a0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,249 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug unit tests in library 'cas_lib'", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--lib", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": [ + "--nocapture" + ], + "cwd": "${workspaceFolder}", + "env": { + "RUST_BACKTRACE": "1" + }, + "console": "integratedTerminal" + }, + + // Integration tests + { + "name": "Debug integration test: asymmetric", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=asymmetric", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: compression", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=compression", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: digital_signatures", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=digital_signatures", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: hashers", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=hashers", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: http", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=http", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: hybrid", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=hybrid", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: key_exchange", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=key_exchange", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: message", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=message", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: password_hashers", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=password_hashers", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: pqc", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=pqc", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: signatures", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=signatures", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: sponges", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=sponges", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: symmetric", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=symmetric", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5d2a5de..5f24576 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cas-lib" -version = "0.2.66" +version = "0.2.67" edition = "2021" description = "A function wrapper layer for RustCrypto and Dalek-Cryptography. Intended to be used in FFI situations with a global heap deallactor at the top level project." license = "Apache-2.0" @@ -34,9 +34,15 @@ hkdf = "0.12.4" chacha20poly1305 = "0.10.1" slh-dsa = "0.0.3" ml-kem = "0.2.1" +reqwest = { version = "0.12.24", features = ["json", "cookies", "rustls-tls"] } +serde = "1.0.228" +tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread"] } +url = "2.5.7" +once_cell = "1.21.3" [profile.dev.package.num-bigint-dig] opt-level = 3 [build-dependencies] napi-build = "1" + diff --git a/src/http/mod.rs b/src/http/mod.rs new file mode 100644 index 0000000..1a5732c --- /dev/null +++ b/src/http/mod.rs @@ -0,0 +1,96 @@ +use reqwest::{Client, cookie::Jar}; +use std::sync::{Arc, Mutex}; +use url::Url; + +pub mod types; +use crate::http::types::{BenchmarkRequest}; + +static API_KEY: Mutex = Mutex::new(String::new()); +static BASE_URL: Mutex = Mutex::new(String::new()); + +static TOKEN: Mutex = Mutex::new(String::new()); +static REFRESH_TOKEN: Mutex = Mutex::new(String::new()); +static BENCHMARK_SENDER_CLIENT: Mutex> = Mutex::new(None); + +fn create_benchmark_sender_client(token: String, refresh_token: String) -> Client { + let cookie_store = Arc::new(Jar::default()); + let base_url = Url::parse(BASE_URL.lock().unwrap().as_str()).unwrap(); + cookie_store.add_cookie_str(&format!("Token={}; Path=/", token), &base_url); + cookie_store.add_cookie_str(&format!("RefreshToken={}; Path=/", refresh_token), &base_url); + Client::builder() + .cookie_provider(cookie_store) + .build() + .unwrap() +} + +fn determine_api_route() -> String { + let base_url = BASE_URL.lock().unwrap(); + if base_url.contains("cryptographicapiservices.com") { + "api/userapi".to_string() + } else { + "api".to_string() + } +} + +pub async fn set_api_key_in_cache(api_key: String) { + let mut key = API_KEY.lock().unwrap(); + *key = api_key.clone(); + set_tokens_in_cache(api_key).await; +} + +pub fn set_base_url_in_cache(base_url: String) { + let mut url = BASE_URL.lock().unwrap(); + *url = base_url +} + +pub async fn set_tokens_in_cache(api_key: String) { + let client = Client::new(); + let base_url = BASE_URL.lock().unwrap().clone(); + let url = format!("{}/{}/APIKey/GetToken", base_url, determine_api_route()); + let response_task = client + .get(url) + .header("Authorization", api_key) + .send() + .await; + let response = response_task.unwrap().json::().await; + match response { + Ok(auth_response) => { + { + let mut token = TOKEN.lock().unwrap(); + *token = auth_response.token.clone(); + } + { + let mut refresh = REFRESH_TOKEN.lock().unwrap(); + *refresh = auth_response.refresh_token.clone(); + } + { + let mut bench_client = BENCHMARK_SENDER_CLIENT.lock().unwrap(); + *bench_client = Some(create_benchmark_sender_client( + auth_response.token, + auth_response.refresh_token, + )); + } + } + + Err(_) => { + *TOKEN.lock().unwrap() = String::new(); + *REFRESH_TOKEN.lock().unwrap() = String::new(); + } + } +} + +pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, method_name: String) { + let payload = BenchmarkRequest { + class_name, + method_name, + time_in_milliseconds, + }; + let base_url = BASE_URL.lock().unwrap().clone(); + let client = BENCHMARK_SENDER_CLIENT.lock().unwrap().as_ref().unwrap().clone(); + + let response = client + .post(format!("{}/{}/Benchmark", base_url, determine_api_route())) + .json(&payload) + .send() + .await; +} \ No newline at end of file diff --git a/src/http/types/mod.rs b/src/http/types/mod.rs new file mode 100644 index 0000000..419ffa9 --- /dev/null +++ b/src/http/types/mod.rs @@ -0,0 +1,18 @@ +use serde::Serialize; + +pub mod runtime; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BenchmarkRequest { + pub class_name: String, + pub method_name: String, + pub time_in_milliseconds: i64 +} + +#[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthResponse { + pub token: String, + pub refresh_token: String +} \ No newline at end of file diff --git a/src/http/types/runtime.rs b/src/http/types/runtime.rs new file mode 100644 index 0000000..60d1bfc --- /dev/null +++ b/src/http/types/runtime.rs @@ -0,0 +1,11 @@ + +use once_cell::sync::Lazy; +use tokio::runtime::Runtime; + +pub static RUNTIME: Lazy = Lazy::new(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(4) + .build() + .unwrap() +}); \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 65b9cfa..58136d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,4 +62,6 @@ pub mod pqc { pub mod ml_kem; pub mod cas_pqc; pub mod slh_dsa; -} \ No newline at end of file +} + +pub mod http; \ No newline at end of file