From 4adb48fbbc92ef0fced86dbea2c0c0a69c6e9411 Mon Sep 17 00:00:00 2001 From: dougal <147946567+roucc@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:42:40 +0000 Subject: [PATCH] b2: fix "expected a FileSseMode but found: ''" 94deb6bd6f3f9615 b2: Add Server-Side encryption support From the commit above, without setting SSE, rclone would send invalid SSE requests with empty strings. This is as omitempty only works with struct pointers not structs. --- backend/b2/api/types.go | 40 ++++++++++++++++++++-------------------- backend/b2/b2.go | 4 ++-- backend/b2/upload.go | 6 +++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/backend/b2/api/types.go b/backend/b2/api/types.go index ab4b221ec..784013ca6 100644 --- a/backend/b2/api/types.go +++ b/backend/b2/api/types.go @@ -269,11 +269,11 @@ type GetFileInfoRequest struct { // // Example: { "src_last_modified_millis" : "1452802803026", "large_file_sha1" : "a3195dc1e7b46a2ff5da4b3c179175b75671e80d", "color": "blue" } type StartLargeFileRequest struct { - BucketID string `json:"bucketId"` // The ID of the bucket that the file will go in. - Name string `json:"fileName"` // The name of the file. See Files for requirements on file names. - ContentType string `json:"contentType"` // The MIME type of the content of the file, which will be returned in the Content-Type header when downloading the file. Use the Content-Type b2/x-auto to automatically set the stored Content-Type post upload. In the case where a file extension is absent or the lookup fails, the Content-Type is set to application/octet-stream. - Info map[string]string `json:"fileInfo"` // A JSON object holding the name/value pairs for the custom file info. - ServerSideEncryption ServerSideEncryption `json:"serverSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption + BucketID string `json:"bucketId"` // The ID of the bucket that the file will go in. + Name string `json:"fileName"` // The name of the file. See Files for requirements on file names. + ContentType string `json:"contentType"` // The MIME type of the content of the file, which will be returned in the Content-Type header when downloading the file. Use the Content-Type b2/x-auto to automatically set the stored Content-Type post upload. In the case where a file extension is absent or the lookup fails, the Content-Type is set to application/octet-stream. + Info map[string]string `json:"fileInfo"` // A JSON object holding the name/value pairs for the custom file info. + ServerSideEncryption *ServerSideEncryption `json:"serverSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption } // StartLargeFileResponse is the response to StartLargeFileRequest @@ -334,25 +334,25 @@ type CancelLargeFileResponse struct { // CopyFileRequest is as passed to b2_copy_file type CopyFileRequest struct { - SourceID string `json:"sourceFileId"` // The ID of the source file being copied. - Name string `json:"fileName"` // The name of the new file being created. - Range string `json:"range,omitempty"` // The range of bytes to copy. If not provided, the whole source file will be copied. - MetadataDirective string `json:"metadataDirective,omitempty"` // The strategy for how to populate metadata for the new file: COPY or REPLACE - ContentType string `json:"contentType,omitempty"` // The MIME type of the content of the file (REPLACE only) - Info map[string]string `json:"fileInfo,omitempty"` // This field stores the metadata that will be stored with the file. (REPLACE only) - DestBucketID string `json:"destinationBucketId,omitempty"` // The destination ID of the bucket if set, if not the source bucket will be used - SourceServerSideEncryption ServerSideEncryption `json:"sourceServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the source file - DestinationServerSideEncryption ServerSideEncryption `json:"destinationServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the destination file + SourceID string `json:"sourceFileId"` // The ID of the source file being copied. + Name string `json:"fileName"` // The name of the new file being created. + Range string `json:"range,omitempty"` // The range of bytes to copy. If not provided, the whole source file will be copied. + MetadataDirective string `json:"metadataDirective,omitempty"` // The strategy for how to populate metadata for the new file: COPY or REPLACE + ContentType string `json:"contentType,omitempty"` // The MIME type of the content of the file (REPLACE only) + Info map[string]string `json:"fileInfo,omitempty"` // This field stores the metadata that will be stored with the file. (REPLACE only) + DestBucketID string `json:"destinationBucketId,omitempty"` // The destination ID of the bucket if set, if not the source bucket will be used + SourceServerSideEncryption *ServerSideEncryption `json:"sourceServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the source file + DestinationServerSideEncryption *ServerSideEncryption `json:"destinationServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the destination file } // CopyPartRequest is the request for b2_copy_part - the response is UploadPartResponse type CopyPartRequest struct { - SourceID string `json:"sourceFileId"` // The ID of the source file being copied. - LargeFileID string `json:"largeFileId"` // The ID of the large file the part will belong to, as returned by b2_start_large_file. - PartNumber int64 `json:"partNumber"` // Which part this is (starting from 1) - Range string `json:"range,omitempty"` // The range of bytes to copy. If not provided, the whole source file will be copied. - SourceServerSideEncryption ServerSideEncryption `json:"sourceServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the source file - DestinationServerSideEncryption ServerSideEncryption `json:"destinationServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the destination file + SourceID string `json:"sourceFileId"` // The ID of the source file being copied. + LargeFileID string `json:"largeFileId"` // The ID of the large file the part will belong to, as returned by b2_start_large_file. + PartNumber int64 `json:"partNumber"` // Which part this is (starting from 1) + Range string `json:"range,omitempty"` // The range of bytes to copy. If not provided, the whole source file will be copied. + SourceServerSideEncryption *ServerSideEncryption `json:"sourceServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the source file + DestinationServerSideEncryption *ServerSideEncryption `json:"destinationServerSideEncryption,omitempty"` // A JSON object holding values related to Server-Side Encryption for the destination file } // UpdateBucketRequest describes a request to modify a B2 bucket diff --git a/backend/b2/b2.go b/backend/b2/b2.go index 4bf4a2a5a..7d1df41f3 100644 --- a/backend/b2/b2.go +++ b/backend/b2/b2.go @@ -1514,8 +1514,8 @@ func (f *Fs) copy(ctx context.Context, dstObj *Object, srcObj *Object, newInfo * CustomerKey: f.opt.SSECustomerKeyBase64, CustomerKeyMd5: f.opt.SSECustomerKeyMD5, } - request.SourceServerSideEncryption = serverSideEncryptionConfig - request.DestinationServerSideEncryption = serverSideEncryptionConfig + request.SourceServerSideEncryption = &serverSideEncryptionConfig + request.DestinationServerSideEncryption = &serverSideEncryptionConfig } if newInfo == nil { request.MetadataDirective = "COPY" diff --git a/backend/b2/upload.go b/backend/b2/upload.go index bc35ad3c5..3034ca174 100644 --- a/backend/b2/upload.go +++ b/backend/b2/upload.go @@ -145,7 +145,7 @@ func (f *Fs) newLargeUpload(ctx context.Context, o *Object, in io.Reader, src fs request.Info = newInfo.Info } if o.fs.opt.SSECustomerKey != "" && o.fs.opt.SSECustomerKeyMD5 != "" { - request.ServerSideEncryption = api.ServerSideEncryption{ + request.ServerSideEncryption = &api.ServerSideEncryption{ Mode: "SSE-C", Algorithm: o.fs.opt.SSECustomerAlgorithm, CustomerKey: o.fs.opt.SSECustomerKeyBase64, @@ -356,8 +356,8 @@ func (up *largeUpload) copyChunk(ctx context.Context, part int, partSize int64) CustomerKey: up.o.fs.opt.SSECustomerKeyBase64, CustomerKeyMd5: up.o.fs.opt.SSECustomerKeyMD5, } - request.SourceServerSideEncryption = serverSideEncryptionConfig - request.DestinationServerSideEncryption = serverSideEncryptionConfig + request.SourceServerSideEncryption = &serverSideEncryptionConfig + request.DestinationServerSideEncryption = &serverSideEncryptionConfig } var response api.UploadPartResponse resp, err := up.f.srv.CallJSON(ctx, &opts, &request, &response)