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:
2026-09-09 21:02:21 +02:00
parent 030ce6a1e5
commit 98bfac718f
10 changed files with 571 additions and 91 deletions
+5 -5
View File
@@ -135,6 +135,7 @@ impl SanctumFile {
dek: Arc<Zeroizing<[u8; 32]>>,
format_version: u32,
last_activity: Arc<AtomicU64>,
append: bool,
) -> Self {
let meta = SanctumMetaData {
is_dir: node.is_dir,
@@ -143,10 +144,12 @@ impl SanctumFile {
modified_at: UNIX_EPOCH + Duration::from_secs(node.modified_at),
};
let cursor = if append { node.size } else { 0 };
Self {
node_id: node.id,
file_size: node.size,
cursor: 0,
cursor,
db,
dek,
meta,
@@ -634,6 +637,7 @@ impl DavFileSystem for SanctumFs {
self.dek.clone(),
self.format_version,
self.last_activity.clone(),
options.append,
);
Ok(Box::new(file) as Box<dyn DavFile>)
})
@@ -649,7 +653,6 @@ impl DavFileSystem for SanctumFs {
}
Box::pin(async move {
self.touch();
let path_str = Self::path_to_str(path);
let node = self
.resolve_path(&path_str)?
@@ -688,9 +691,6 @@ impl DavFileSystem for SanctumFs {
Box::pin(async move {
let path_str = Self::path_to_str(path);
if path_str != "/" && !path_str.is_empty() {
self.touch();
}
let node = self
.resolve_path(&path_str)?
.ok_or(FsError::NotFound)?;