-
-
Notifications
You must be signed in to change notification settings - Fork 88
feat: adaugat structura de baza pentru ipfs_plugin #324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 15 commits
6abd836
29c1c5e
cb3572e
f2bd2b5
12db078
b3a0ae8
8f2ac30
bfa24f2
a68daaf
7c130ee
f6f579b
eeb8772
02f0364
387034e
23d95a0
1a0fb47
5ba0476
9fea777
59a632e
aa3a2f7
06580f3
f7e7842
7dfa5b3
a165ef8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| use crate::crypto::{self, Cipher}; | ||
| use crate::crypto::write::CryptoWrite; // Rezolvă eroarea cu .finish() | ||
| use shush_rs::SecretVec; | ||
| use std::io::{Read, Write, Cursor}; | ||
|
|
||
| pub struct IpfsCipher { | ||
| key: SecretVec<u8>, | ||
| cipher: Cipher, | ||
| } | ||
|
|
||
| impl IpfsCipher { | ||
| /// Inițializează plugin-ul cu o cheie sigură și cipher-ul implicit | ||
| pub fn new(secret_key: Vec<u8>) -> Self { | ||
| Self { | ||
| key: SecretVec::from(secret_key), | ||
| cipher: Cipher::ChaCha20Poly1305, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoding
Generated by Claude Code |
||
| } | ||
| } | ||
|
|
||
| /// Criptează un bloc de date utilizând un Cursor pentru a simula un fișier în memorie | ||
| pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, String> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This re-implements the one-shot pattern that already exists in
Related: Generated by Claude Code |
||
| if data.is_empty() { | ||
| return Ok(Vec::new()); | ||
| } | ||
|
|
||
| // Folosim Cursor pentru a implementa Write + Seek + Read cerute de autor | ||
| let memory_file = Cursor::new(Vec::new()); | ||
| let mut writer = crypto::create_write(memory_file, self.cipher, &self.key); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every Because Cheaper: cache reusable cipher state in Generated by Claude Code |
||
|
|
||
| writer.write_all(data) | ||
| .map_err(|e| format!("Eroare la scrierea datelor IPFS: {:?}", e))?; | ||
|
|
||
| // .finish() returnează obiectul intern (Cursor-ul) în caz de succes | ||
| let finished_cursor = writer.finish() | ||
| .map_err(|e| format!("Eroare la finalizarea criptării IPFS: {:?}", e))?; | ||
|
|
||
| // Extriem vectorul de bytes din interiorul cursorului | ||
| Ok(finished_cursor.into_inner()) | ||
| } | ||
|
|
||
| /// Decriptează un bloc de date utilizând CryptoRead-ul nativ din rencfs | ||
| pub fn decrypt(&self, encrypted_data: &[u8]) -> Result<Vec<u8>, String> { | ||
| if encrypted_data.is_empty() { | ||
| return Ok(Vec::new()); | ||
| } | ||
|
|
||
| let mut reader = crypto::create_read(encrypted_data, self.cipher, &self.key); | ||
| let mut decrypted_data = Vec::new(); | ||
|
|
||
| reader.read_to_end(&mut decrypted_data) | ||
| .map_err(|e| format!("Eroare la decriptarea datelor IPFS: {:?}", e))?; | ||
|
|
||
| Ok(decrypted_data) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_ipfs_encryption_decryption() { | ||
| // Generăm o cheie de test de 32 de bytes (pentru ChaCha20Poly1305) | ||
| let test_key = vec![0u8; 32]; | ||
| let cipher = IpfsCipher::new(test_key); | ||
|
|
||
| let original_data = b"Date secrete trimise prin IPFS cu CID unic!"; | ||
|
|
||
| // 1. Criptăm datele | ||
| let encrypted = cipher.encrypt(original_data).expect("Criptarea a eșuat"); | ||
| assert_ne!(original_data.to_vec(), encrypted, "Datele criptate nu trebuie să fie la fel ca cele originale"); | ||
|
|
||
| // 2. Decriptăm datele înapoi | ||
| let decrypted = cipher.decrypt(&encrypted).expect("Decriptarea a eșuat"); | ||
| assert_eq!(original_data.to_vec(), decrypted, "Datele decriptate nu se potrivesc cu cele originale"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||||||||||
| use crate::ipfs_plugin::IpfsCipher; | ||||||||||||||
| use argon2::password_hash::rand_core::RngCore; | ||||||||||||||
| use async_trait::async_trait; | ||||||||||||||
| use futures_util::TryStreamExt; | ||||||||||||||
|
|
@@ -574,6 +575,7 @@ pub struct EncryptedFs { | |||||||||||||
| sizes_read: Mutex<HashMap<u64, AtomicU64>>, | ||||||||||||||
| requested_read: Mutex<HashMap<u64, AtomicU64>>, | ||||||||||||||
| read_only: bool, | ||||||||||||||
| pub ipfs_cipher: Option<IpfsCipher>, | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dead public field on the security-critical core type.
Suggest deleting the field (and Generated by Claude Code |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| impl EncryptedFs { | ||||||||||||||
|
|
@@ -627,6 +629,7 @@ impl EncryptedFs { | |||||||||||||
| sizes_read: Mutex::default(), | ||||||||||||||
| requested_read: Mutex::default(), | ||||||||||||||
| read_only, | ||||||||||||||
| ipfs_cipher: None, | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| let arc = Arc::new(fs); | ||||||||||||||
|
|
@@ -638,6 +641,8 @@ impl EncryptedFs { | |||||||||||||
| arc.ensure_root_exists().await?; | ||||||||||||||
|
|
||||||||||||||
| Ok(arc) | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| } | ||||||||||||||
|
Comment on lines
643
to
644
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Generated by Claude Code |
||||||||||||||
|
|
||||||||||||||
| pub fn exists(&self, ino: u64) -> bool { | ||||||||||||||
|
|
@@ -2462,6 +2467,9 @@ impl EncryptedFs { | |||||||||||||
| return ino; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| pub fn enable_ipfs_plugin(&mut self, master_key: Vec<u8>) { | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is uncallable — the feature is dead on arrival.
If core support is truly needed, this has to fit the type's ownership model: a constructor parameter, or an interior-mutability slot — though see the other comments for why the plugin probably shouldn't touch Generated by Claude Code |
||||||||||||||
| self.ipfs_cipher = Some(IpfsCipher::new(master_key)); | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Taking the master key as a plain CLAUDE.md states secrets are "held in
If the plugin needs a key, accept Generated by Claude Code |
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| pub struct CopyFileRangeReq { | ||||||||||||||
| src_ino: u64, | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -326,3 +326,6 @@ pub const fn is_debug() -> bool { | |
| } | ||
| false | ||
| } | ||
|
|
||
| #[path = "../ipfs_plugin/src/lib.rs"] | ||
| pub mod ipfs_plugin; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
The repo already has the right pattern for an integration bridge: Generated by Claude Code |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No key-length validation — a wrong-length key panics (and aborts the process in release builds) despite the
Resultsignature.new()accepts anyVec<u8>. The firstencrypt()/decrypt()then reachesUnboundKey::new(algorithm, &key.expose_secret()).expect("unbound key")(src/crypto/write.rs:92, and the.unwrap()at read.rs:93); ring returnsErrfor any key that isn't exactlyCipher::key_len()bytes (32 here), so the.expectfires. With[profile.release] panic = "abort", that's a full process abort — from a safe public API whose methods promiseResult<_, String>. Every existing key path avoids this becausecrypto::derive_keysizes the key tocipher.key_len(); this constructor is the only way to smuggle in a bad length.Validate in
new()(returnResultand checksecret_key.len() == self.cipher.key_len()), or better, acceptSecretVec<u8>from a source that already guarantees the length.Generated by Claude Code