mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-07 04:25:54 +00:00
fix(s3): align encrypted checksums and multipart completion (#7025)
* fix(s3): align encrypted checksum handling * test(s3): align multipart SSE-C completion * fix(ecstore): scope startup helper to tests
This commit is contained in:
@@ -37,7 +37,9 @@ use rustfs_filemeta::{FileInfo, MetaCacheEntriesSorted, ObjectPartInfo, RestoreS
|
||||
use rustfs_rio::Checksum;
|
||||
use rustfs_utils::CompressionAlgorithm;
|
||||
use rustfs_utils::http::headers::AMZ_OBJECT_TAGGING;
|
||||
use rustfs_utils::http::{AMZ_BUCKET_REPLICATION_STATUS, AMZ_RESTORE, AMZ_STORAGE_CLASS};
|
||||
use rustfs_utils::http::{
|
||||
AMZ_BUCKET_REPLICATION_STATUS, AMZ_RESTORE, AMZ_STORAGE_CLASS, SUFFIX_PLAINTEXT_CHECKSUM, get_consistent_str,
|
||||
};
|
||||
use rustfs_utils::path::decode_dir_object;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
||||
@@ -1771,9 +1771,10 @@ impl ObjectInfo {
|
||||
}
|
||||
|
||||
if let Some(data) = &self.checksum {
|
||||
if self.is_encrypted() {
|
||||
if self.is_encrypted() && get_consistent_str(&self.user_defined, SUFFIX_PLAINTEXT_CHECKSUM) != Some("true") {
|
||||
// Object-level encrypted checksum bytes require SSE decrypt material,
|
||||
// so do not expose them as plaintext checksum headers here. The
|
||||
// unless RustFS marked the stored bytes as plaintext. Do not expose
|
||||
// unmarked bytes as checksum headers here. The
|
||||
// `false` multipart flag feeds the response-path COMPOSITE
|
||||
// fallback; callers that need accurate multipart routing must
|
||||
// consult `is_multipart()` instead of this value.
|
||||
@@ -2479,6 +2480,31 @@ mod tests {
|
||||
assert!(checksums.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt_checksums_reads_marked_rustfs_encrypted_object_checksum() {
|
||||
let checksum = rustfs_rio::Checksum::new_from_data(rustfs_rio::ChecksumType::CRC32, b"encrypted-object")
|
||||
.expect("test checksum should be valid");
|
||||
let checksum_key = checksum.checksum_type.to_string();
|
||||
let expected_checksum = checksum.encoded.clone();
|
||||
let mut user_defined =
|
||||
HashMap::from([(rustfs_utils::http::headers::AMZ_SERVER_SIDE_ENCRYPTION.to_string(), "AES256".to_string())]);
|
||||
rustfs_utils::http::insert_str(&mut user_defined, SUFFIX_PLAINTEXT_CHECKSUM, "true".to_string());
|
||||
assert_eq!(user_defined.get("x-rustfs-internal-plaintext-checksum").map(String::as_str), Some("true"));
|
||||
assert_eq!(user_defined.get("x-minio-internal-plaintext-checksum").map(String::as_str), Some("true"));
|
||||
let info = ObjectInfo {
|
||||
checksum: Some(checksum.to_bytes(&[])),
|
||||
user_defined: Arc::new(user_defined),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (checksums, is_multipart) = info
|
||||
.decrypt_checksums(0, &HeaderMap::new())
|
||||
.expect("marked RustFS checksum should decode");
|
||||
|
||||
assert!(!is_multipart);
|
||||
assert_eq!(checksums.get(&checksum_key), Some(&expected_checksum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt_checksums_keeps_encrypted_multipart_flag_false_for_response_paths() {
|
||||
let checksum = rustfs_rio::Checksum::new_from_data(rustfs_rio::ChecksumType::CRC32, b"encrypted-object")
|
||||
|
||||
Reference in New Issue
Block a user