| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/google/uuid" | 
					
						
							| 
									
										
										
										
											2020-07-15 00:38:05 +08:00
										 |  |  | 	"github.com/minio/minio-go/v7/pkg/encrypt" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/crypto" | 
					
						
							|  |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // set encryption options for pass through to backend in the case of gateway and UserDefined metadata
 | 
					
						
							|  |  |  | func getDefaultOpts(header http.Header, copySource bool, metadata map[string]string) (opts ObjectOptions, err error) { | 
					
						
							|  |  |  | 	var clientKey [32]byte | 
					
						
							|  |  |  | 	var sse encrypt.ServerSide | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	opts = ObjectOptions{UserDefined: metadata} | 
					
						
							|  |  |  | 	if copySource { | 
					
						
							|  |  |  | 		if crypto.SSECopy.IsRequested(header) { | 
					
						
							|  |  |  | 			clientKey, err = crypto.SSECopy.ParseHTTP(header) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if sse, err = encrypt.NewSSEC(clientKey[:]); err != nil { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			opts.ServerSideEncryption = encrypt.SSECopy(sse) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if crypto.SSEC.IsRequested(header) { | 
					
						
							|  |  |  | 		clientKey, err = crypto.SSEC.ParseHTTP(header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if sse, err = encrypt.NewSSEC(clientKey[:]); err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		opts.ServerSideEncryption = sse | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if crypto.S3.IsRequested(header) || (metadata != nil && crypto.S3.IsEncrypted(metadata)) { | 
					
						
							|  |  |  | 		opts.ServerSideEncryption = encrypt.NewSSE() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-28 03:22:34 +08:00
										 |  |  | 	if v, ok := header[xhttp.MinIOSourceProxyRequest]; ok { | 
					
						
							|  |  |  | 		opts.ProxyHeaderSet = true | 
					
						
							|  |  |  | 		opts.ProxyRequest = strings.Join(v, "") == "true" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 	if _, ok := header[xhttp.MinIOSourceReplicationRequest]; ok { | 
					
						
							|  |  |  | 		opts.ReplicationRequest = true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get ObjectOptions for GET calls from encryption headers
 | 
					
						
							|  |  |  | func getOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		encryption encrypt.ServerSide | 
					
						
							|  |  |  | 		opts       ObjectOptions | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var partNumber int | 
					
						
							|  |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2021-08-08 13:43:01 +08:00
										 |  |  | 	if pn := r.Form.Get(xhttp.PartNumber); pn != "" { | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 		partNumber, err = strconv.Atoi(pn) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if partNumber <= 0 { | 
					
						
							|  |  |  | 			return opts, errInvalidArgument | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 13:43:01 +08:00
										 |  |  | 	vid := strings.TrimSpace(r.Form.Get(xhttp.VersionID)) | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	if vid != "" && vid != nullVersionID { | 
					
						
							|  |  |  | 		_, err := uuid.Parse(vid) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.LogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2020-11-29 13:15:45 +08:00
										 |  |  | 			return opts, InvalidVersionID{ | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 				Bucket:    bucket, | 
					
						
							|  |  |  | 				Object:    object, | 
					
						
							|  |  |  | 				VersionID: vid, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if GlobalGatewaySSE.SSEC() && crypto.SSEC.IsRequested(r.Header) { | 
					
						
							|  |  |  | 		key, err := crypto.SSEC.ParseHTTP(r.Header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		derivedKey := deriveClientKey(key, bucket, object) | 
					
						
							|  |  |  | 		encryption, err = encrypt.NewSSEC(derivedKey[:]) | 
					
						
							|  |  |  | 		logger.CriticalIf(ctx, err) | 
					
						
							|  |  |  | 		return ObjectOptions{ | 
					
						
							|  |  |  | 			ServerSideEncryption: encryption, | 
					
						
							|  |  |  | 			VersionID:            vid, | 
					
						
							|  |  |  | 			PartNumber:           partNumber, | 
					
						
							|  |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 09:43:14 +08:00
										 |  |  | 	deletePrefix := false | 
					
						
							|  |  |  | 	if d := r.Header.Get(xhttp.MinIOForceDelete); d != "" { | 
					
						
							|  |  |  | 		if b, err := strconv.ParseBool(d); err == nil { | 
					
						
							|  |  |  | 			deletePrefix = b | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return opts, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	// default case of passing encryption headers to backend
 | 
					
						
							|  |  |  | 	opts, err = getDefaultOpts(r.Header, false, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return opts, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-16 09:43:14 +08:00
										 |  |  | 	opts.DeletePrefix = deletePrefix | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	opts.PartNumber = partNumber | 
					
						
							|  |  |  | 	opts.VersionID = vid | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 	delMarker := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceDeleteMarker)) | 
					
						
							|  |  |  | 	if delMarker != "" { | 
					
						
							| 
									
										
										
										
											2020-11-13 04:10:59 +08:00
										 |  |  | 		switch delMarker { | 
					
						
							|  |  |  | 		case "true": | 
					
						
							|  |  |  | 			opts.DeleteMarker = true | 
					
						
							|  |  |  | 		case "false": | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			err = fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceDeleteMarker, fmt.Errorf("DeleteMarker should be true or false")) | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 			logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							| 
									
										
										
										
											2020-11-13 04:10:59 +08:00
										 |  |  | 				Err:    err, | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-06-07 06:14:56 +08:00
										 |  |  | 	opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object) | 
					
						
							| 
									
										
										
										
											2022-05-09 07:50:31 +08:00
										 |  |  | 	opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(bucket, object) | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	return opts, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func delOpts(ctx context.Context, r *http.Request, bucket, object string) (opts ObjectOptions, err error) { | 
					
						
							|  |  |  | 	opts, err = getOpts(ctx, r, bucket, object) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return opts, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-07 10:05:28 +08:00
										 |  |  | 	opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object) | 
					
						
							| 
									
										
										
										
											2022-06-07 06:14:56 +08:00
										 |  |  | 	opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(bucket, object) | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 	delMarker := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceDeleteMarker)) | 
					
						
							|  |  |  | 	if delMarker != "" { | 
					
						
							| 
									
										
										
										
											2020-11-13 04:10:59 +08:00
										 |  |  | 		switch delMarker { | 
					
						
							|  |  |  | 		case "true": | 
					
						
							|  |  |  | 			opts.DeleteMarker = true | 
					
						
							|  |  |  | 		case "false": | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			err = fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceDeleteMarker, fmt.Errorf("DeleteMarker should be true or false")) | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 			logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							| 
									
										
										
										
											2020-11-13 04:10:59 +08:00
										 |  |  | 				Err:    err, | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mtime := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceMTime)) | 
					
						
							|  |  |  | 	if mtime != "" { | 
					
						
							| 
									
										
										
										
											2020-12-19 03:37:28 +08:00
										 |  |  | 		opts.MTime, err = time.Parse(time.RFC3339Nano, mtime) | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceMTime, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		opts.MTime = UTCNow() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	return opts, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get ObjectOptions for PUT calls from encryption headers and metadata
 | 
					
						
							|  |  |  | func putOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { | 
					
						
							| 
									
										
										
										
											2022-05-07 10:05:28 +08:00
										 |  |  | 	versioned := globalBucketVersioningSys.PrefixEnabled(bucket, object) | 
					
						
							|  |  |  | 	versionSuspended := globalBucketVersioningSys.PrefixSuspended(bucket, object) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 13:43:01 +08:00
										 |  |  | 	vid := strings.TrimSpace(r.Form.Get(xhttp.VersionID)) | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	if vid != "" && vid != nullVersionID { | 
					
						
							|  |  |  | 		_, err := uuid.Parse(vid) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.LogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2020-11-29 13:15:45 +08:00
										 |  |  | 			return opts, InvalidVersionID{ | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 				Bucket:    bucket, | 
					
						
							|  |  |  | 				Object:    object, | 
					
						
							|  |  |  | 				VersionID: vid, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-10-01 04:36:37 +08:00
										 |  |  | 		if !versioned { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("VersionID specified %s, but versioning not enabled on  %s", opts.VersionID, bucket), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-03 09:32:22 +08:00
										 |  |  | 	mtimeStr := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceMTime)) | 
					
						
							| 
									
										
										
										
											2020-11-20 10:43:58 +08:00
										 |  |  | 	mtime := UTCNow() | 
					
						
							| 
									
										
										
										
											2020-10-03 09:32:22 +08:00
										 |  |  | 	if mtimeStr != "" { | 
					
						
							|  |  |  | 		mtime, err = time.Parse(time.RFC3339, mtimeStr) | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceMTime, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 	retaintimeStr := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceObjectRetentionTimestamp)) | 
					
						
							|  |  |  | 	retaintimestmp := mtime | 
					
						
							|  |  |  | 	if retaintimeStr != "" { | 
					
						
							|  |  |  | 		retaintimestmp, err = time.Parse(time.RFC3339, retaintimeStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceObjectRetentionTimestamp, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lholdtimeStr := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceObjectLegalHoldTimestamp)) | 
					
						
							|  |  |  | 	lholdtimestmp := mtime | 
					
						
							|  |  |  | 	if lholdtimeStr != "" { | 
					
						
							|  |  |  | 		lholdtimestmp, err = time.Parse(time.RFC3339, lholdtimeStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceObjectLegalHoldTimestamp, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tagtimeStr := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceTaggingTimestamp)) | 
					
						
							|  |  |  | 	taggingtimestmp := mtime | 
					
						
							|  |  |  | 	if tagtimeStr != "" { | 
					
						
							|  |  |  | 		taggingtimestmp, err = time.Parse(time.RFC3339, tagtimeStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceTaggingTimestamp, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 08:32:24 +08:00
										 |  |  | 	etag := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceETag)) | 
					
						
							|  |  |  | 	if etag != "" { | 
					
						
							|  |  |  | 		if metadata == nil { | 
					
						
							| 
									
										
										
										
											2020-09-11 02:37:22 +08:00
										 |  |  | 			metadata = make(map[string]string, 1) | 
					
						
							| 
									
										
										
										
											2020-08-13 08:32:24 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		metadata["etag"] = etag | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-13 04:12:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	// In the case of multipart custom format, the metadata needs to be checked in addition to header to see if it
 | 
					
						
							|  |  |  | 	// is SSE-S3 encrypted, primarily because S3 protocol does not require SSE-S3 headers in PutObjectPart calls
 | 
					
						
							|  |  |  | 	if GlobalGatewaySSE.SSES3() && (crypto.S3.IsRequested(r.Header) || crypto.S3.IsEncrypted(metadata)) { | 
					
						
							|  |  |  | 		return ObjectOptions{ | 
					
						
							|  |  |  | 			ServerSideEncryption: encrypt.NewSSE(), | 
					
						
							|  |  |  | 			UserDefined:          metadata, | 
					
						
							|  |  |  | 			VersionID:            vid, | 
					
						
							|  |  |  | 			Versioned:            versioned, | 
					
						
							| 
									
										
										
										
											2021-08-17 22:50:00 +08:00
										 |  |  | 			VersionSuspended:     versionSuspended, | 
					
						
							| 
									
										
										
										
											2020-10-03 09:32:22 +08:00
										 |  |  | 			MTime:                mtime, | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if GlobalGatewaySSE.SSEC() && crypto.SSEC.IsRequested(r.Header) { | 
					
						
							|  |  |  | 		opts, err = getOpts(ctx, r, bucket, object) | 
					
						
							|  |  |  | 		opts.VersionID = vid | 
					
						
							|  |  |  | 		opts.Versioned = versioned | 
					
						
							| 
									
										
										
										
											2021-08-17 22:50:00 +08:00
										 |  |  | 		opts.VersionSuspended = versionSuspended | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 		opts.UserDefined = metadata | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if crypto.S3KMS.IsRequested(r.Header) { | 
					
						
							|  |  |  | 		keyID, context, err := crypto.S3KMS.ParseHTTP(r.Header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return ObjectOptions{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		sseKms, err := encrypt.NewSSEKMS(keyID, context) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return ObjectOptions{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return ObjectOptions{ | 
					
						
							|  |  |  | 			ServerSideEncryption: sseKms, | 
					
						
							|  |  |  | 			UserDefined:          metadata, | 
					
						
							|  |  |  | 			VersionID:            vid, | 
					
						
							|  |  |  | 			Versioned:            versioned, | 
					
						
							| 
									
										
										
										
											2021-08-17 22:50:00 +08:00
										 |  |  | 			VersionSuspended:     versionSuspended, | 
					
						
							| 
									
										
										
										
											2020-10-03 09:32:22 +08:00
										 |  |  | 			MTime:                mtime, | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 		}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// default case of passing encryption headers and UserDefined metadata to backend
 | 
					
						
							|  |  |  | 	opts, err = getDefaultOpts(r.Header, false, metadata) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return opts, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	opts.VersionID = vid | 
					
						
							|  |  |  | 	opts.Versioned = versioned | 
					
						
							| 
									
										
										
										
											2021-08-17 22:50:00 +08:00
										 |  |  | 	opts.VersionSuspended = versionSuspended | 
					
						
							| 
									
										
										
										
											2020-10-03 09:32:22 +08:00
										 |  |  | 	opts.MTime = mtime | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 	opts.ReplicationSourceLegalholdTimestamp = lholdtimestmp | 
					
						
							|  |  |  | 	opts.ReplicationSourceRetentionTimestamp = retaintimestmp | 
					
						
							|  |  |  | 	opts.ReplicationSourceTaggingTimestamp = taggingtimestmp | 
					
						
							| 
									
										
										
										
											2020-07-09 08:36:56 +08:00
										 |  |  | 	return opts, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get ObjectOptions for Copy calls with encryption headers provided on the target side and source side metadata
 | 
					
						
							|  |  |  | func copyDstOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { | 
					
						
							|  |  |  | 	return putOpts(ctx, r, bucket, object, metadata) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get ObjectOptions for Copy calls with encryption headers provided on the source side
 | 
					
						
							|  |  |  | func copySrcOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		ssec encrypt.ServerSide | 
					
						
							|  |  |  | 		opts ObjectOptions | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if GlobalGatewaySSE.SSEC() && crypto.SSECopy.IsRequested(r.Header) { | 
					
						
							|  |  |  | 		key, err := crypto.SSECopy.ParseHTTP(r.Header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		derivedKey := deriveClientKey(key, bucket, object) | 
					
						
							|  |  |  | 		ssec, err = encrypt.NewSSEC(derivedKey[:]) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return ObjectOptions{ServerSideEncryption: encrypt.SSECopy(ssec)}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// default case of passing encryption headers to backend
 | 
					
						
							|  |  |  | 	opts, err := getDefaultOpts(r.Header, false, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return opts, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return opts, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-30 22:44:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // get ObjectOptions for CompleteMultipart calls
 | 
					
						
							|  |  |  | func completeMultipartOpts(ctx context.Context, r *http.Request, bucket, object string) (opts ObjectOptions, err error) { | 
					
						
							|  |  |  | 	mtimeStr := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceMTime)) | 
					
						
							|  |  |  | 	mtime := UTCNow() | 
					
						
							|  |  |  | 	if mtimeStr != "" { | 
					
						
							|  |  |  | 		mtime, err = time.Parse(time.RFC3339, mtimeStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return opts, InvalidArgument{ | 
					
						
							|  |  |  | 				Bucket: bucket, | 
					
						
							|  |  |  | 				Object: object, | 
					
						
							|  |  |  | 				Err:    fmt.Errorf("Unable to parse %s, failed with %w", xhttp.MinIOSourceMTime, err), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	opts.MTime = mtime | 
					
						
							| 
									
										
										
										
											2021-09-09 13:25:23 +08:00
										 |  |  | 	opts.UserDefined = make(map[string]string) | 
					
						
							| 
									
										
										
										
											2021-06-30 22:44:24 +08:00
										 |  |  | 	return opts, nil | 
					
						
							|  |  |  | } |