extern crate mauth_core; use mauth_core::signer::Signer; use mauth_core::verifier::Verifier; use serde::Deserialize; use std::fs; use std::path::Path; const TEST_SUITE_PATH: &str = "tests/mauth-protocol-test-suite/"; #[derive(Deserialize)] struct RequestShape { verb: String, url: String, body: Option, body_filepath: Option, } #[derive(Deserialize)] struct Config { app_uuid: String, request_time: u64, private_key_file: String, } fn test_signer( signer: &Signer, version: u8, timestamp: &str, protocol_path: &Path, test_case: &str, ) -> Result<(), String> { let test_case_path = protocol_path.join(test_case); let req_path = test_case_path.join(format!("{test_case}.req")); let sig_path = test_case_path.join(format!("{test_case}.sig")); let req: RequestShape = serde_json::from_slice(&fs::read(Path::new(&req_path)).unwrap()).unwrap(); let sig = match fs::read_to_string(Path::new(&sig_path)) { Ok(sig) => sig, _ => { return Ok(()); } }; let (path, query) = req.url.split_once('?').unwrap_or((&req.url, "")); let body_data = match (req.body, req.body_filepath) { (Some(direct_str), None) => direct_str.as_bytes().to_vec(), (None, Some(filename_str)) => fs::read(test_case_path.join(filename_str)).unwrap(), _ => vec![], }; let result = signer .sign_string(version, req.verb, path, query, &body_data, timestamp) .unwrap(); if sig == result { Ok(()) } else { Err(format!("[{test_case}] result: {result}, expected: {sig}")) } } fn test_verifier( verifier: &Verifier, version: u8, timestamp: &str, protocol_path: &Path, test_case: &str, ) -> Result<(), String> { let test_case_path = protocol_path.join(test_case); let req_path = test_case_path.join(format!("{test_case}.req")); let sig_path = test_case_path.join(format!("{test_case}.sig")); let req: RequestShape = serde_json::from_slice(&fs::read(Path::new(&req_path)).unwrap()).unwrap(); let sig = match fs::read_to_string(Path::new(&sig_path)) { Ok(sig) => sig, _ => { return Ok(()); } }; let (path, query) = req.url.split_once('?').unwrap_or((&req.url, "")); let body_data = match (req.body, req.body_filepath) { (Some(direct_str), None) => direct_str.as_bytes().to_vec(), (None, Some(filename_str)) => fs::read(test_case_path.join(filename_str)).unwrap(), _ => vec![], }; verifier .verify_signature(version, req.verb, path, query, &body_data, timestamp, sig) .map_err(|_| format!("[{test_case}] failed")) } #[test] fn mws_protocol_signer_test() -> Result<(), String> { let test_suite_path = Path::new(TEST_SUITE_PATH); let protocols_path = test_suite_path.join("protocols"); let protocol_path = protocols_path.join("MWS"); let config_path = test_suite_path.join("signing-config.json"); let config: Config = serde_json::from_slice(&fs::read(config_path).unwrap()).unwrap(); let private_key = fs::read_to_string(Path::new(&test_suite_path.join(config.private_key_file))).unwrap(); let signer = Signer::new(config.app_uuid, private_key).unwrap(); let timestamp = config.request_time.to_string(); fs::read_dir(&protocol_path) .unwrap() .map(|r| { let r_path = r.unwrap().path(); ( r_path.clone(), r_path.file_name().unwrap().to_str().unwrap().to_string(), ) }) .try_for_each(|(_, name)| { test_signer(&signer, 1, ×tamp, protocol_path.as_path(), &name) })?; Ok(()) } #[test] fn mwsv2_protocol_signer_test() -> Result<(), String> { let test_suite_path = Path::new(TEST_SUITE_PATH); let protocols_path = test_suite_path.join("protocols"); let protocol_path = protocols_path.join("MWSV2"); let config_path = test_suite_path.join("signing-config.json"); let config: Config = serde_json::from_slice(&fs::read(config_path).unwrap()).unwrap(); let private_key = fs::read_to_string(Path::new(&test_suite_path.join(config.private_key_file))).unwrap(); let signer = Signer::new(config.app_uuid, private_key).unwrap(); let timestamp = config.request_time.to_string(); fs::read_dir(&protocol_path) .unwrap() .map(|r| { let r_path = r.unwrap().path(); ( r_path.clone(), r_path.file_name().unwrap().to_str().unwrap().to_string(), ) }) .try_for_each(|(_, name)| { test_signer(&signer, 2, ×tamp, protocol_path.as_path(), &name) })?; Ok(()) } #[test] fn mws_protocol_verifier_test() -> Result<(), String> { let test_suite_path = Path::new(TEST_SUITE_PATH); let protocols_path = test_suite_path.join("protocols"); let protocol_path = protocols_path.join("MWS"); let config_path = test_suite_path.join("signing-config.json"); let config: Config = serde_json::from_slice(&fs::read(config_path).unwrap()).unwrap(); let public_key = fs::read_to_string(Path::new( &test_suite_path.join("signing-params/rsa-key-pub"), )) .unwrap(); let verifier = Verifier::new(config.app_uuid, public_key).unwrap(); let timestamp = config.request_time.to_string(); fs::read_dir(&protocol_path) .unwrap() .map(|r| { let r_path = r.unwrap().path(); ( r_path.clone(), r_path.file_name().unwrap().to_str().unwrap().to_string(), ) }) .try_for_each(|(_, name)| { test_verifier(&verifier, 1, ×tamp, protocol_path.as_path(), &name) })?; Ok(()) } #[test] fn mwsv2_protocol_verifier_test() -> Result<(), String> { let test_suite_path = Path::new(TEST_SUITE_PATH); let protocols_path = test_suite_path.join("protocols"); let protocol_path = protocols_path.join("MWSV2"); let config_path = test_suite_path.join("signing-config.json"); let config: Config = serde_json::from_slice(&fs::read(config_path).unwrap()).unwrap(); let public_key = fs::read_to_string(Path::new( &test_suite_path.join("signing-params/rsa-key-pub"), )) .unwrap(); let verifier = Verifier::new(config.app_uuid, public_key).unwrap(); let timestamp = config.request_time.to_string(); fs::read_dir(&protocol_path) .unwrap() .map(|r| { let r_path = r.unwrap().path(); ( r_path.clone(), r_path.file_name().unwrap().to_str().unwrap().to_string(), ) }) .try_for_each(|(_, name)| { test_verifier(&verifier, 2, ×tamp, protocol_path.as_path(), &name) })?; Ok(()) }