// file: ks-wallet/tests/public_api.rs // version: 3 //! External crate-root contract tests for the `ks-wallet` public API. fn write_native_wallet_fixture( path: &std::path::Path, alias: &str, marker: u8, ) -> std::string::String { let public_key = solana_pubkey::Pubkey::new_from_array([marker; 32]); let alias_bytes = alias.as_bytes(); let alias_length = u8::try_from(alias_bytes.len()).unwrap_or_else(|_| panic!("fixture alias must fit u8")); let header_length = 72_u16 + u16::from(alias_length); let ciphertext = vec![marker.wrapping_add(3); 80]; let mut bytes = std::vec::Vec::new(); bytes.extend_from_slice(b"KSWALLET"); bytes.extend_from_slice(&1_u16.to_le_bytes()); bytes.extend_from_slice(&header_length.to_le_bytes()); bytes.extend_from_slice(&0_u16.to_le_bytes()); bytes.push(1); bytes.push(0x13); bytes.push(1); bytes.push(16); bytes.push(24); bytes.push(alias_length); bytes.extend_from_slice(&[0_u8; 4]); bytes.extend_from_slice(&65_536_u32.to_le_bytes()); bytes.extend_from_slice(&3_u32.to_le_bytes()); bytes.extend_from_slice(&4_u32.to_le_bytes()); bytes.extend_from_slice(&80_u32.to_le_bytes()); let public_key_bytes = public_key.to_bytes(); bytes.extend_from_slice(&public_key_bytes); bytes.extend_from_slice(alias_bytes); bytes.extend_from_slice(&[marker.wrapping_add(1); 16]); bytes.extend_from_slice(&[marker.wrapping_add(2); 24]); bytes.extend_from_slice(ciphertext.as_slice()); std::fs::write(path, bytes) .unwrap_or_else(|error| panic!("native fixture must be writable: {error}")); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600)) .unwrap_or_else(|error| panic!("native fixture permissions must be set: {error}")); } return public_key.to_string(); } #[tokio::test] async fn crate_root_exposes_multi_wallet_discovery_without_path_disclosure() { assert_eq!(ks_wallet::KSWALLET_FILE_EXTENSION, "kswallet"); let directory = tempfile::tempdir() .unwrap_or_else(|error| panic!("temporary directory must exist: {error}")); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import std::fs::set_permissions(directory.path(), std::fs::Permissions::from_mode(0o700)) .unwrap_or_else(|error| { panic!("wallet fixture directory permissions must be set: {error}") }); } let manager = ks_wallet::WalletManager::new(directory.path()) .unwrap_or_else(|error| panic!("unexpected manager error: {error}")); let path = directory.path().join("public-api.kswallet"); let expected_public_key = write_native_wallet_fixture(&path, "public-api", 37); let handles = manager .scan() .await .unwrap_or_else(|error| panic!("scan must succeed: {error}")); assert_eq!(handles.len(), 1); assert_eq!(handles[0].alias().as_str(), "public-api"); assert_eq!(handles[0].public_key(), expected_public_key); assert_eq!(handles[0].format_version(), 1); assert_eq!(handles[0].identity().persistence, ks_wallet::WalletPersistence::Persistent); assert!(!format!("{:?}", handles[0]).contains(directory.path().to_string_lossy().as_ref())); } #[test] fn crate_root_exposes_non_secret_temporary_identity() { let alias = ks_wallet::WalletAlias::parse("public-identity") .unwrap_or_else(|error| panic!("unexpected alias error: {error}")); let wallet = ks_wallet::TemporaryWallet::generate(alias.clone()); let identity: ks_wallet::WalletIdentity = wallet.identity(); let summary: ks_wallet::WalletSummary = wallet.summary(); assert_eq!(identity.alias, alias); assert_eq!(identity.public_key, summary.public_key); assert_eq!(identity.persistence, ks_wallet::WalletPersistence::Temporary); }