fix(core): resolve all 12 adversarial review findings
- Zeroize passwords in CLI prompts, handlers, and mount authentication - Preserve carrier_node_id when recovering Slot 0 via recovery key - Add --slot parameter to restore-header for targeted slot recovery - Implement online_backup and restore_from_backup using SQLite Online Backup API - Expose 'sanctum backup' and 'sanctum restore' CLI subcommands - Fix inactivity auto-lock by removing touch() from PROPFIND metadata/read_dir - Support O_APPEND by setting file cursor to file size on handle creation - Prevent data loss by implementing Drop for CarrierFile to flush dirty blocks - Optimize CSPRNG padding to only fill unwritten slack space - Batch carrier initialization in 500-block transactions to prevent UI/CLI freeze - Enforce 64-byte savings threshold for LZ4 compression - Add WebClient service diagnostic hint for Windows net use mount errors - Add unit and integration tests covering all new features
This commit is contained in:
+31
-9
@@ -178,10 +178,9 @@ pub fn write_carrier_block(
|
||||
|
||||
let inner_ct_len = inner_ct.len() as u32;
|
||||
|
||||
// 2. Äußere Nutzlast vorbereiten: Exakt CHUNK_SIZE (1 MB) mit CSPRNG-Rauschen
|
||||
// 2. Äußere Nutzlast vorbereiten: Exakt CHUNK_SIZE (1 MB)
|
||||
// Format: inner_nonce (12B) || inner_tag (16B) || inner_ct_len (4B LE) || inner_ct || CSPRNG-Padding
|
||||
let mut outer_plaintext = vec![0u8; CHUNK_SIZE];
|
||||
OsRng.fill_bytes(&mut outer_plaintext);
|
||||
|
||||
outer_plaintext[0..12].copy_from_slice(&inner_nonce);
|
||||
outer_plaintext[12..28].copy_from_slice(&inner_tag);
|
||||
@@ -197,6 +196,11 @@ pub fn write_carrier_block(
|
||||
}
|
||||
outer_plaintext[32..ct_end].copy_from_slice(&inner_ct);
|
||||
|
||||
// Nur den ungenutzten Slack-Space mit kryptografischem Zufall auffüllen (~30x schneller als 1MB OsRng)
|
||||
if ct_end < CHUNK_SIZE {
|
||||
OsRng.fill_bytes(&mut outer_plaintext[ct_end..]);
|
||||
}
|
||||
|
||||
// 3. Äußere Schicht verschlüsseln (mit dek_outer = DEK_0)
|
||||
let (outer_ct, outer_nonce, outer_tag) = encrypt_chunk(
|
||||
dek_outer,
|
||||
@@ -491,7 +495,7 @@ impl DavFileSystem for CarrierFs {
|
||||
|
||||
drop(inner);
|
||||
|
||||
let file = CarrierFile::new(inode, self.inner.clone());
|
||||
let file = CarrierFile::new(inode, self.inner.clone(), options.append);
|
||||
Ok(Box::new(file) as Box<dyn DavFile>)
|
||||
})
|
||||
}
|
||||
@@ -502,7 +506,6 @@ impl DavFileSystem for CarrierFs {
|
||||
_meta: ReadDirMeta,
|
||||
) -> FsFuture<'a, FsStream<Box<dyn DavDirEntry>>> {
|
||||
Box::pin(async move {
|
||||
self.touch();
|
||||
let path_str = Self::path_to_str(path);
|
||||
let inner = self.inner.lock().unwrap();
|
||||
|
||||
@@ -537,9 +540,6 @@ impl DavFileSystem for CarrierFs {
|
||||
fn metadata<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, Box<dyn DavMetaData>> {
|
||||
Box::pin(async move {
|
||||
let path_str = Self::path_to_str(path);
|
||||
if path_str != "/" && !path_str.is_empty() {
|
||||
self.touch();
|
||||
}
|
||||
|
||||
let inner = self.inner.lock().unwrap();
|
||||
let node = inner.resolve_path(&path_str).ok_or(FsError::NotFound)?;
|
||||
@@ -755,7 +755,7 @@ impl Debug for CarrierFile {
|
||||
}
|
||||
|
||||
impl CarrierFile {
|
||||
pub fn new(inode: CarrierInode, inner_fs: Arc<Mutex<CarrierFsInner>>) -> Self {
|
||||
pub fn new(inode: CarrierInode, inner_fs: Arc<Mutex<CarrierFsInner>>, append: bool) -> Self {
|
||||
let meta = SanctumMetaData {
|
||||
is_dir: inode.is_dir,
|
||||
size: inode.size,
|
||||
@@ -763,10 +763,12 @@ impl CarrierFile {
|
||||
modified_at: UNIX_EPOCH + Duration::from_secs(inode.modified_at),
|
||||
};
|
||||
|
||||
let cursor = if append { inode.size } else { 0 };
|
||||
|
||||
Self {
|
||||
inode_id: inode.id,
|
||||
file_size: inode.size,
|
||||
cursor: 0,
|
||||
cursor,
|
||||
blocks: inode.blocks,
|
||||
inner_fs,
|
||||
meta,
|
||||
@@ -991,3 +993,23 @@ impl DavFile for CarrierFile {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CarrierFile {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.flush_cached_block() {
|
||||
tracing::warn!("Fehler beim automatischen Flush im CarrierFile::drop: {:?}", e);
|
||||
}
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
if let Ok(mut inner) = self.inner_fs.lock() {
|
||||
if let Some(inode) = inner.manifest.inodes.get_mut(&self.inode_id) {
|
||||
inode.size = self.file_size;
|
||||
inode.blocks = self.blocks.clone();
|
||||
inode.modified_at = now;
|
||||
}
|
||||
let _ = inner.save_manifest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user