From ba7672cd5138d1ee187c3a7ebabbbb996a8c984f Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:57:33 +0100 Subject: [PATCH] security: remediate UnboundedAllocation findings --- crates/januskey-cli/src/keys.rs | 2 +- crates/januskey-cli/src/lib.rs | 2 +- crates/januskey-cli/src/main.rs | 2 +- crates/januskey-cli/src/obliteration.rs | 2 +- crates/januskey-cli/src/operations.rs | 6 +++--- crates/januskey-cli/tests/aspect_test.rs | 2 +- crates/januskey-cli/tests/concurrency_test.rs | 4 ++-- crates/januskey-cli/tests/e2e_test.rs | 8 ++++---- crates/januskey-cli/tests/p2p_test.rs | 4 ++-- crates/reversible-core/src/metadata.rs | 2 +- crates/reversible-core/src/transaction.rs | 2 +- src/januskey/src/keys.rs | 2 +- src/januskey/src/lib.rs | 2 +- src/januskey/src/main.rs | 2 +- src/januskey/src/metadata.rs | 2 +- src/januskey/src/obliteration.rs | 2 +- src/januskey/src/operations.rs | 6 +++--- src/januskey/src/transaction.rs | 2 +- tests/p2p/component_p2p_test.rs | 4 ++-- 19 files changed, 29 insertions(+), 29 deletions(-) diff --git a/crates/januskey-cli/src/keys.rs b/crates/januskey-cli/src/keys.rs index 236a025..23ed5c1 100644 --- a/crates/januskey-cli/src/keys.rs +++ b/crates/januskey-cli/src/keys.rs @@ -531,7 +531,7 @@ impl KeyManager { fn load_store_raw(&self) -> Result { let path = self.store_path.join("keystore.jks"); - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; let store: KeyStoreData = serde_json::from_str(&content)?; Ok(store) } diff --git a/crates/januskey-cli/src/lib.rs b/crates/januskey-cli/src/lib.rs index 2eaf363..87c341e 100644 --- a/crates/januskey-cli/src/lib.rs +++ b/crates/januskey-cli/src/lib.rs @@ -78,7 +78,7 @@ impl Config { pub fn load(dir: &std::path::Path) -> Self { let config_path = dir.join(".januskey").join("config.json"); if config_path.exists() { - if let Ok(content) = std::fs::read_to_string(&config_path) { + if let Ok(content) = ({ use std::io::Read; std::fs::File::open(&config_path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }) { if let Ok(config) = serde_json::from_str(&content) { return config; } diff --git a/crates/januskey-cli/src/main.rs b/crates/januskey-cli/src/main.rs index 281d5d7..f1c4c3e 100644 --- a/crates/januskey-cli/src/main.rs +++ b/crates/januskey-cli/src/main.rs @@ -392,7 +392,7 @@ fn cmd_modify( // Preview changes let mut changes = Vec::new(); for file in &files { - let content = fs::read_to_string(file)?; + let content = ({ use std::io::Read; std::fs::File::open(file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; let new_content = if global { content.replace(&search, &replace) } else { diff --git a/crates/januskey-cli/src/obliteration.rs b/crates/januskey-cli/src/obliteration.rs index 2232e32..c3b5fb5 100644 --- a/crates/januskey-cli/src/obliteration.rs +++ b/crates/januskey-cli/src/obliteration.rs @@ -146,7 +146,7 @@ impl ObliterationManager { /// Create or open an obliteration manager pub fn new(log_path: PathBuf) -> Result { let log = if log_path.exists() { - let content = fs::read_to_string(&log_path)?; + let content = ({ use std::io::Read; std::fs::File::open(&log_path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content) .map_err(|e| JanusError::MetadataCorrupted(e.to_string()))? } else { diff --git a/crates/januskey-cli/src/operations.rs b/crates/januskey-cli/src/operations.rs index ce8174e..1be35f4 100644 --- a/crates/januskey-cli/src/operations.rs +++ b/crates/januskey-cli/src/operations.rs @@ -513,7 +513,7 @@ mod tests { executor.undo(&delete_meta.id).unwrap(); assert!(test_file.exists()); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "hello world"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "hello world"); } #[test] @@ -533,13 +533,13 @@ mod tests { }) .unwrap(); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "modified content"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "modified content"); // Undo the modify let mut executor = OperationExecutor::new(&content_store, &mut metadata_store); executor.undo(&modify_meta.id).unwrap(); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "original content"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "original content"); } #[test] diff --git a/crates/januskey-cli/tests/aspect_test.rs b/crates/januskey-cli/tests/aspect_test.rs index bdc4890..de1b776 100644 --- a/crates/januskey-cli/tests/aspect_test.rs +++ b/crates/januskey-cli/tests/aspect_test.rs @@ -134,7 +134,7 @@ fn obliterated_key_record_marked_revoked() { // Verify key record reflects revocation let key_content = - fs::read_to_string(base.join(".jk/keys").join(format!("{}.json", key_id))) + ({ use std::io::Read; std::fs::File::open(base.join(".jk/keys").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).join(format!("{}.json", key_id))) .expect("Read key record"); assert!( key_content.contains("revoked"), diff --git a/crates/januskey-cli/tests/concurrency_test.rs b/crates/januskey-cli/tests/concurrency_test.rs index 10d8a4d..9dc7da9 100644 --- a/crates/januskey-cli/tests/concurrency_test.rs +++ b/crates/januskey-cli/tests/concurrency_test.rs @@ -164,7 +164,7 @@ fn transaction_isolation_uncommitted_invisible() { // Reader may see the file (filesystem is not transactional), // but we verify the transaction itself is still "active" not "committed" - let tx_read = fs::read_to_string(base.join(".jk/transactions/001.json")) + let tx_read = ({ use std::io::Read; std::fs::File::open(base.join(".jk/transactions/001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })) .expect("Read transaction"); assert!( tx_read.contains("\"active\""), @@ -404,7 +404,7 @@ fn concurrent_commit_rollback_no_corruption() { // Verify each transaction is in a valid terminal state for entry in fs::read_dir(base.join(".jk/transactions")).expect("Read dir") { let entry = entry.expect("Dir entry"); - let content = fs::read_to_string(entry.path()).expect("Read tx file"); + let content = ({ use std::io::Read; std::fs::File::open(entry.path().and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })).expect("Read tx file"); let is_valid = content.contains("\"committed\"") || content.contains("\"rolled_back\""); assert!( is_valid, diff --git a/crates/januskey-cli/tests/e2e_test.rs b/crates/januskey-cli/tests/e2e_test.rs index 4de3071..ba52b92 100644 --- a/crates/januskey-cli/tests/e2e_test.rs +++ b/crates/januskey-cli/tests/e2e_test.rs @@ -81,13 +81,13 @@ fn full_key_lifecycle_single_key() { assert_eq!(retrieved, key_material, "Retrieved content must match original"); // Step 5: Verify attestation references the key - let attest_read = fs::read_to_string(base.join(".jk/attestation/0001.json")) + let attest_read = ({ use std::io::Read; std::fs::File::open(base.join(".jk/attestation/0001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })) .expect("Read attestation"); assert!(attest_read.contains(key_id), "Attestation must contain key ID"); assert!(attest_read.contains(&key_hash), "Attestation must contain content hash"); // Verify key record exists - let key_read = fs::read_to_string(base.join(".jk/keys/001.json")) + let key_read = ({ use std::io::Read; std::fs::File::open(base.join(".jk/keys/001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })) .expect("Read key record"); assert!(key_read.contains(key_id), "Key record must contain ID"); } @@ -167,7 +167,7 @@ fn full_key_lifecycle_multi_key_transaction() { // Verify transaction is committed let tx_read = - fs::read_to_string(base.join(".jk/transactions/001.json")).expect("Read tx"); + ({ use std::io::Read; std::fs::File::open(base.join(".jk/transactions/001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })).expect("Read tx"); assert!(tx_read.contains("committed"), "Transaction must be committed"); } @@ -359,7 +359,7 @@ fn corrupted_attestation_entry_detected() { .expect("Write malformed entry"); // Attempt to read and parse - let read_result = fs::read_to_string(base.join(".jk/attestation/0001.json")) + let read_result = ({ use std::io::Read; std::fs::File::open(base.join(".jk/attestation/0001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })) .expect("Read file"); let parse_result = serde_json::from_str::(&read_result); diff --git a/crates/januskey-cli/tests/p2p_test.rs b/crates/januskey-cli/tests/p2p_test.rs index d7381f7..fc7300c 100644 --- a/crates/januskey-cli/tests/p2p_test.rs +++ b/crates/januskey-cli/tests/p2p_test.rs @@ -101,7 +101,7 @@ fn key_operation_creates_attestation_entry() { std::fs::write(attest_path.join("0001.json"), &entry).unwrap(); // Verify attestation references the key - let read_back = std::fs::read_to_string(attest_path.join("0001.json")).unwrap(); + let read_back = ({ use std::io::Read; std::fs::File::open(attest_path.join("0001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })).unwrap(); assert!( read_back.contains(key_id), "Attestation must reference key ID" @@ -132,7 +132,7 @@ fn attestation_chain_integrity() { // Verify chain: each entry's content hashes to the next's prev_hash let entries: Vec = (0..3) - .map(|i| std::fs::read_to_string(attest_path.join(format!("{:04}.json", i))).unwrap()) + .map(|i| ({ use std::io::Read; std::fs::File::open(attest_path.join(format!("{:04}.json", i).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }))).unwrap()) .collect(); for i in 1..entries.len() { diff --git a/crates/reversible-core/src/metadata.rs b/crates/reversible-core/src/metadata.rs index 1c5b008..7806411 100644 --- a/crates/reversible-core/src/metadata.rs +++ b/crates/reversible-core/src/metadata.rs @@ -256,7 +256,7 @@ impl MetadataStore { /// Create or open a metadata store pub fn new(path: PathBuf) -> Result { let log = if path.exists() { - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content) .map_err(|e| ReversibleError::MetadataCorrupted(e.to_string()))? } else { diff --git a/crates/reversible-core/src/transaction.rs b/crates/reversible-core/src/transaction.rs index a21d473..a1d1891 100644 --- a/crates/reversible-core/src/transaction.rs +++ b/crates/reversible-core/src/transaction.rs @@ -121,7 +121,7 @@ impl TransactionManager { /// Create or open a transaction manager pub fn new(path: PathBuf) -> Result { let log = if path.exists() { - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content) .map_err(|e| ReversibleError::MetadataCorrupted(e.to_string()))? } else { diff --git a/src/januskey/src/keys.rs b/src/januskey/src/keys.rs index 561bc6e..0bc8d3f 100644 --- a/src/januskey/src/keys.rs +++ b/src/januskey/src/keys.rs @@ -531,7 +531,7 @@ impl KeyManager { fn load_store_raw(&self) -> Result { let path = self.store_path.join("keystore.jks"); - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; let store: KeyStoreData = serde_json::from_str(&content)?; Ok(store) } diff --git a/src/januskey/src/lib.rs b/src/januskey/src/lib.rs index adb19ca..171ae30 100644 --- a/src/januskey/src/lib.rs +++ b/src/januskey/src/lib.rs @@ -61,7 +61,7 @@ impl Config { pub fn load(dir: &std::path::Path) -> Self { let config_path = dir.join(".januskey").join("config.json"); if config_path.exists() { - if let Ok(content) = std::fs::read_to_string(&config_path) { + if let Ok(content) = ({ use std::io::Read; std::fs::File::open(&config_path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }) { if let Ok(config) = serde_json::from_str(&content) { return config; } diff --git a/src/januskey/src/main.rs b/src/januskey/src/main.rs index 88f37ad..0802977 100644 --- a/src/januskey/src/main.rs +++ b/src/januskey/src/main.rs @@ -370,7 +370,7 @@ fn cmd_modify( // Preview changes let mut changes = Vec::new(); for file in &files { - let content = fs::read_to_string(file)?; + let content = ({ use std::io::Read; std::fs::File::open(file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; let new_content = if global { content.replace(&search, &replace) } else { diff --git a/src/januskey/src/metadata.rs b/src/januskey/src/metadata.rs index fead27a..ae9d1e4 100644 --- a/src/januskey/src/metadata.rs +++ b/src/januskey/src/metadata.rs @@ -224,7 +224,7 @@ impl MetadataStore { /// Create or open a metadata store pub fn new(path: PathBuf) -> Result { let log = if path.exists() { - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content).map_err(|e| JanusError::MetadataCorrupted(e.to_string()))? } else { OperationLog::default() diff --git a/src/januskey/src/obliteration.rs b/src/januskey/src/obliteration.rs index dedb700..e0d0208 100644 --- a/src/januskey/src/obliteration.rs +++ b/src/januskey/src/obliteration.rs @@ -146,7 +146,7 @@ impl ObliterationManager { /// Create or open an obliteration manager pub fn new(log_path: PathBuf) -> Result { let log = if log_path.exists() { - let content = fs::read_to_string(&log_path)?; + let content = ({ use std::io::Read; std::fs::File::open(&log_path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content) .map_err(|e| JanusError::MetadataCorrupted(e.to_string()))? } else { diff --git a/src/januskey/src/operations.rs b/src/januskey/src/operations.rs index ce8174e..1be35f4 100644 --- a/src/januskey/src/operations.rs +++ b/src/januskey/src/operations.rs @@ -513,7 +513,7 @@ mod tests { executor.undo(&delete_meta.id).unwrap(); assert!(test_file.exists()); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "hello world"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "hello world"); } #[test] @@ -533,13 +533,13 @@ mod tests { }) .unwrap(); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "modified content"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "modified content"); // Undo the modify let mut executor = OperationExecutor::new(&content_store, &mut metadata_store); executor.undo(&modify_meta.id).unwrap(); - assert_eq!(fs::read_to_string(&test_file).unwrap(), "original content"); + assert_eq!(({ use std::io::Read; std::fs::File::open(&test_file).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }).unwrap(), "original content"); } #[test] diff --git a/src/januskey/src/transaction.rs b/src/januskey/src/transaction.rs index eddb86d..3c9085a 100644 --- a/src/januskey/src/transaction.rs +++ b/src/januskey/src/transaction.rs @@ -112,7 +112,7 @@ impl TransactionManager { /// Create or open a transaction manager pub fn new(path: PathBuf) -> Result { let log = if path.exists() { - let content = fs::read_to_string(&path)?; + let content = ({ use std::io::Read; std::fs::File::open(&path).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })?; serde_json::from_str(&content) .map_err(|e| JanusError::MetadataCorrupted(e.to_string()))? } else { diff --git a/tests/p2p/component_p2p_test.rs b/tests/p2p/component_p2p_test.rs index 2f681cd..fd520f7 100644 --- a/tests/p2p/component_p2p_test.rs +++ b/tests/p2p/component_p2p_test.rs @@ -82,7 +82,7 @@ mod p2p_tests { std::fs::write(attest_path.join("0001.json"), &entry).unwrap(); // Verify attestation references the key - let read_back = std::fs::read_to_string(attest_path.join("0001.json")).unwrap(); + let read_back = ({ use std::io::Read; std::fs::File::open(attest_path.join("0001.json").and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) })).unwrap(); assert!(read_back.contains(key_id), "Attestation must reference key ID"); } @@ -108,7 +108,7 @@ mod p2p_tests { // Verify chain: each entry's content hashes to the next's prev_hash let entries: Vec = (0..3) .map(|i| { - std::fs::read_to_string(attest_path.join(format!("{:04}.json", i))).unwrap() + ({ use std::io::Read; std::fs::File::open(attest_path.join(format!("{:04}.json", i).and_then(|mut f| { let mut buf = String::new(); f.take(10 * 1024 * 1024).read_to_string(&mut buf)?; Ok(buf) }) }))).unwrap() }) .collect();