diff --git a/krillnotes-core/src/core/workspace/attachments.rs b/krillnotes-core/src/core/workspace/attachments.rs index c31d559a..3cfa7419 100644 --- a/krillnotes-core/src/core/workspace/attachments.rs +++ b/krillnotes-core/src/core/workspace/attachments.rs @@ -421,7 +421,8 @@ impl Workspace { if trash_path.exists() { std::fs::rename(&trash_path, &enc_path)?; } - let salt_bytes = hex::decode(&meta.salt).unwrap_or_else(|_| meta.salt.as_bytes().to_vec()); + let salt_bytes = hex::decode(&meta.salt) + .map_err(|_| KrillnotesError::AttachmentEncryption("invalid attachment salt hex".into()))?; self.storage.connection().execute( "INSERT OR IGNORE INTO attachments (id, note_id, filename, mime_type, size_bytes, hash_sha256, salt, created_at) diff --git a/krillnotes-core/src/core/workspace/tests.rs b/krillnotes-core/src/core/workspace/tests.rs index 18f4f610..3ee47dc7 100644 --- a/krillnotes-core/src/core/workspace/tests.rs +++ b/krillnotes-core/src/core/workspace/tests.rs @@ -6313,3 +6313,36 @@ fn test_self_authored_ops_have_verified_by() { "Self-authored operations should have verified_by = identity pubkey" ); } + +#[test] +fn test_restore_attachment_rejects_invalid_salt_hex() { + let dir = tempfile::tempdir().unwrap(); + let db_path = dir.path().join("notes.db"); + let mut ws = Workspace::create( + &db_path, + "testpass", + "test-identity", + ed25519_dalek::SigningKey::from_bytes(&[1u8; 32]), + test_gate(), + None, + ) + .unwrap(); + let root_id = ws.list_all_notes().unwrap()[0].id.clone(); + + let bad_meta = AttachmentMeta { + id: "bad-att-id".into(), + note_id: root_id, + filename: "test.txt".into(), + mime_type: Some("text/plain".into()), + size_bytes: 0, + hash_sha256: "0".repeat(64), + salt: "not-valid-hex!!!".into(), + created_at: crate::core::timestamp::UnixSecs::ZERO, + }; + + let err = ws.restore_attachment(&bad_meta).unwrap_err(); + assert!( + matches!(err, crate::KrillnotesError::AttachmentEncryption(_)), + "expected AttachmentEncryption for invalid salt hex, got: {err:?}" + ); +} diff --git a/krillnotes-core/src/core/workspace/undo.rs b/krillnotes-core/src/core/workspace/undo.rs index 8632005e..3c80e8be 100644 --- a/krillnotes-core/src/core/workspace/undo.rs +++ b/krillnotes-core/src/core/workspace/undo.rs @@ -511,9 +511,8 @@ impl Workspace { } } for att in attachments { - // salt is hex-encoded in AttachmentMeta; DB stores raw bytes. - let salt_bytes = - hex::decode(&att.salt).unwrap_or_else(|_| att.salt.as_bytes().to_vec()); + let salt_bytes = hex::decode(&att.salt) + .map_err(|_| KrillnotesError::AttachmentEncryption("invalid attachment salt hex".into()))?; tx.execute( "INSERT OR IGNORE INTO attachments (id, note_id, filename, mime_type, size_bytes, hash_sha256, salt, created_at)