mirror of
https://github.com/minio/minio.git
synced 2025-02-27 21:39:15 -05:00
Fix CopyObjectPart broken source encryption support (#6699)
Current master didn't support CopyObjectPart when source was encrypted, this PR fixes this by allowing range CopySource decryption at different sequence numbers. Fixes #6698
This commit is contained in:
parent
bab4c90c45
commit
555d54371c
@ -332,7 +332,7 @@ func DecryptRequestWithSequenceNumberR(client io.Reader, h http.Header, bucket,
|
||||
|
||||
// DecryptCopyRequestR - same as DecryptCopyRequest, but with a
|
||||
// Reader
|
||||
func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string, metadata map[string]string) (io.Reader, error) {
|
||||
func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string, seqNumber uint32, metadata map[string]string) (io.Reader, error) {
|
||||
var (
|
||||
key []byte
|
||||
err error
|
||||
@ -343,7 +343,7 @@ func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string,
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return newDecryptReader(client, key, bucket, object, 0, metadata)
|
||||
return newDecryptReader(client, key, bucket, object, seqNumber, metadata)
|
||||
}
|
||||
|
||||
func newDecryptReader(client io.Reader, key []byte, bucket, object string, seqNumber uint32, metadata map[string]string) (io.Reader, error) {
|
||||
@ -365,17 +365,6 @@ func newDecryptReaderWithObjectKey(client io.Reader, objectEncryptionKey []byte,
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
// GetEncryptedOffsetLength - returns encrypted offset and length
|
||||
// along with sequence number
|
||||
func GetEncryptedOffsetLength(startOffset, length int64, objInfo ObjectInfo) (seqNumber uint32, encStartOffset, encLength int64) {
|
||||
if !isEncryptedMultipart(objInfo) {
|
||||
seqNumber, encStartOffset, encLength = getEncryptedSinglePartOffsetLength(startOffset, length, objInfo)
|
||||
return
|
||||
}
|
||||
seqNumber, encStartOffset, encLength = getEncryptedMultipartsOffsetLength(startOffset, length, objInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// DecryptBlocksRequestR - same as DecryptBlocksRequest but with a
|
||||
// reader
|
||||
func DecryptBlocksRequestR(inputReader io.Reader, h http.Header, offset,
|
||||
@ -389,7 +378,7 @@ func DecryptBlocksRequestR(inputReader io.Reader, h http.Header, offset,
|
||||
var reader io.Reader
|
||||
var err error
|
||||
if copySource {
|
||||
reader, err = DecryptCopyRequestR(inputReader, h, bucket, object, oi.UserDefined)
|
||||
reader, err = DecryptCopyRequestR(inputReader, h, bucket, object, seqNumber, oi.UserDefined)
|
||||
} else {
|
||||
reader, err = DecryptRequestWithSequenceNumberR(inputReader, h, bucket, object, seqNumber, oi.UserDefined)
|
||||
}
|
||||
|
@ -701,30 +701,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
getObjectNInfo = api.CacheAPI().GetObjectNInfo
|
||||
}
|
||||
|
||||
// Get request range.
|
||||
var rs *HTTPRangeSpec
|
||||
rangeHeader := r.Header.Get("x-amz-copy-source-range")
|
||||
if rangeHeader != "" {
|
||||
var parseRangeErr error
|
||||
if rs, parseRangeErr = parseRequestRangeSpec(rangeHeader); parseRangeErr != nil {
|
||||
// Handle only errInvalidRange. Ignore other
|
||||
// parse error and treat it as regular Get
|
||||
// request like Amazon S3.
|
||||
if parseRangeErr == errInvalidRange {
|
||||
writeErrorResponse(w, ErrInvalidRange, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// log the error.
|
||||
logger.LogIf(ctx, parseRangeErr)
|
||||
}
|
||||
}
|
||||
|
||||
var lock = noLock
|
||||
if !cpSrcDstSame {
|
||||
lock = readLock
|
||||
}
|
||||
|
||||
var rs *HTTPRangeSpec
|
||||
gr, err := getObjectNInfo(ctx, srcBucket, srcObject, rs, r.Header, lock, srcOpts)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
@ -1485,8 +1467,11 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||
}
|
||||
|
||||
// Get the object offset & length
|
||||
startOffset, length, _ := rs.GetOffsetLength(actualPartSize)
|
||||
actualPartSize = length
|
||||
startOffset, length, err := rs.GetOffsetLength(actualPartSize)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
/// maximum copy size for multipart objects in a single operation
|
||||
if isMaxAllowedPartSize(length) {
|
||||
@ -1494,8 +1479,8 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||
return
|
||||
}
|
||||
|
||||
actualPartSize = length
|
||||
var reader io.Reader
|
||||
var getLength = length
|
||||
|
||||
var li ListPartsInfo
|
||||
li, err = objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1)
|
||||
@ -1503,6 +1488,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// Read compression metadata preserved in the init multipart for the decision.
|
||||
_, compressPart := li.UserDefined[ReservedMetadataPrefix+"compression"]
|
||||
isCompressed := compressPart
|
||||
@ -1535,7 +1521,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||
|
||||
if objectAPI.IsEncryptionSupported() && !isCompressed {
|
||||
if crypto.IsEncrypted(li.UserDefined) {
|
||||
if !hasServerSideEncryptionHeader(r.Header) {
|
||||
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) {
|
||||
writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL)
|
||||
return
|
||||
}
|
||||
@ -1567,18 +1553,18 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
||||
}
|
||||
|
||||
info := ObjectInfo{Size: length}
|
||||
size := info.EncryptedSize()
|
||||
srcInfo.Reader, err = hash.NewReader(reader, size, "", "", actualPartSize)
|
||||
srcInfo.Reader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", length)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy source object to destination, if source and destination
|
||||
// object is same then only metadata is updated.
|
||||
partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket,
|
||||
dstObject, uploadID, partID, startOffset, getLength, srcInfo, srcOpts, dstOpts)
|
||||
partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket, dstObject, uploadID, partID,
|
||||
startOffset, length, srcInfo, srcOpts, dstOpts)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user