merge: feature/v0.8.1-cleanup-item-build (v0.8.1 wrap-up) — shared encrypt_document_file helper (F1 DRY + F2 zeroize plaintext)

This commit is contained in:
adlee-was-taken
2026-06-20 22:07:38 -04:00
2 changed files with 33 additions and 24 deletions

View File

@@ -3,7 +3,7 @@
//! (`commands/org.rs`). Centralizing it keeps the two surfaces from drifting.
use std::collections::HashMap;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use zeroize::Zeroizing;
@@ -255,23 +255,39 @@ pub(crate) fn build_totp(
})))
}
/// Read a file and encrypt it as an attachment under `key`, deriving its display
/// metadata. The plaintext is held in a `Zeroizing` buffer so it is wiped after
/// encryption. Returns the encrypted blob plus (filename, mime_type, size).
pub(crate) fn encrypt_document_file(
path: &Path,
key: &Zeroizing<[u8; 32]>,
max_bytes: u64,
) -> Result<(EncryptedAttachment, String, String, u64)> {
use relicario_core::encrypt_attachment;
let bytes = Zeroizing::new(
std::fs::read(path).with_context(|| format!("failed to read {}", path.display()))?,
);
let enc = encrypt_attachment(&bytes, key, max_bytes)?;
let filename = path
.file_name()
.ok_or_else(|| anyhow::anyhow!("file path has no filename: {}", path.display()))?
.to_string_lossy()
.into_owned();
let mime_type = crate::parse::guess_mime(&filename);
Ok((enc, filename, mime_type, bytes.len() as u64))
}
pub(crate) fn build_document(
title: String, file: PathBuf, key: &Zeroizing<[u8; 32]>, max_bytes: u64,
) -> Result<(Item, EncryptedAttachment)> {
use relicario_core::item_types::DocumentCore;
use relicario_core::{encrypt_attachment, AttachmentRef};
let bytes = std::fs::read(&file).with_context(|| format!("failed to read {}", file.display()))?;
let enc = encrypt_attachment(&bytes, key, max_bytes)?;
let filename = file.file_name()
.ok_or_else(|| anyhow::anyhow!("file path has no filename: {}", file.display()))?
.to_string_lossy().into_owned();
let mime_type = crate::parse::guess_mime(&filename);
let primary_attachment = enc.id.clone();
use relicario_core::AttachmentRef;
let (enc, filename, mime_type, size) = encrypt_document_file(&file, key, max_bytes)?;
let mut item = Item::new(title, ItemCore::Document(DocumentCore {
filename: filename.clone(), mime_type: mime_type.clone(), primary_attachment: primary_attachment.clone(),
filename: filename.clone(), mime_type: mime_type.clone(), primary_attachment: enc.id.clone(),
}));
item.attachments.push(AttachmentRef {
id: primary_attachment, filename, mime_type, size: bytes.len() as u64, created: item.created,
id: enc.id.clone(), filename, mime_type, size, created: item.created,
});
Ok((item, enc))
}

View File

@@ -1038,25 +1038,18 @@ pub fn run_edit(dir: &Path, query: &str, totp_qr: Option<std::path::PathBuf>, fi
ItemCore::Key(k) => ib::edit_key(k, history)?,
ItemCore::Document(d) => {
if let Some(path) = &file {
let bytes = std::fs::read(path)
.with_context(|| format!("read {}", path.display()))?;
let enc = relicario_core::encrypt_attachment(
&bytes, vault.key(), crate::org_session::DEFAULT_ORG_ATTACHMENT_MAX_BYTES)?;
let (enc, filename, mime_type, size) = ib::encrypt_document_file(
path, vault.key(), crate::org_session::DEFAULT_ORG_ATTACHMENT_MAX_BYTES)?;
vault.remove_item_attachments(&collection, &id)?;
let rel = vault.save_attachment(&collection, &id, &enc)?;
let filename = path
.file_name()
.ok_or_else(|| anyhow::anyhow!("file path has no filename: {}", path.display()))?
.to_string_lossy()
.into_owned();
d.mime_type = crate::parse::guess_mime(&filename);
d.primary_attachment = enc.id.clone();
d.filename = filename.clone();
d.mime_type = mime_type.clone();
d.primary_attachment = enc.id.clone();
new_doc_attachments = Some(vec![relicario_core::AttachmentRef {
id: enc.id,
filename,
mime_type: d.mime_type.clone(),
size: bytes.len() as u64,
mime_type,
size,
created: now_unix(),
}]);
doc_attachment_rel = Some(rel);