You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.6 KiB

package coscrypto
import (
"context"
"fmt"
"io"
"net/http"
"strconv"
"git.ouxuan.net/tommy/cos-go-sdk-v5"
)
type CryptoContext struct {
DataSize int64
PartSize int64
ContentCipher ContentCipher
}
func partSizeIsValid(partSize int64, alignLen int64) bool {
if partSize%alignLen == 0 {
return true
}
return false
}
func (s *CryptoObjectService) InitiateMultipartUpload(ctx context.Context, name string, opt *cos.InitiateMultipartUploadOptions, cryptoCtx *CryptoContext) (*cos.InitiateMultipartUploadResult, *cos.Response, error) {
contentCipher, err := s.cryptoClient.ContentCipherBuilder.ContentCipher()
if err != nil {
return nil, nil, err
}
if !partSizeIsValid(cryptoCtx.PartSize, int64(contentCipher.GetAlignLen())) {
return nil, nil, fmt.Errorf("PartSize is invalid, it should be %v aligned", contentCipher.GetAlignLen())
}
// 添加自定义头部
cryptoCtx.ContentCipher = contentCipher
opt = cos.CloneInitiateMultipartUploadOptions(opt)
if opt.XOptionHeader == nil {
opt.XOptionHeader = &http.Header{}
}
if opt.ContentMD5 != "" {
opt.XOptionHeader.Add(COSClientSideEncryptionUnencryptedContentMD5, opt.ContentMD5)
opt.ContentMD5 = ""
}
if cryptoCtx.DataSize > 0 {
opt.XOptionHeader.Add(COSClientSideEncryptionDataSize, strconv.FormatInt(cryptoCtx.DataSize, 10))
}
opt.XOptionHeader.Add(COSClientSideEncryptionPartSize, strconv.FormatInt(cryptoCtx.PartSize, 10))
opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
addCryptoHeaders(opt.XOptionHeader, contentCipher.GetCipherData())
return s.ObjectService.InitiateMultipartUpload(ctx, name, opt)
}
func (s *CryptoObjectService) UploadPart(ctx context.Context, name, uploadID string, partNumber int, r io.Reader, opt *cos.ObjectUploadPartOptions, cryptoCtx *CryptoContext) (*cos.Response, error) {
if cryptoCtx.PartSize == 0 {
return nil, fmt.Errorf("CryptoContext's PartSize is zero")
}
opt = cos.CloneObjectUploadPartOptions(opt)
if opt.XOptionHeader == nil {
opt.XOptionHeader = &http.Header{}
}
opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
if cryptoCtx.ContentCipher == nil {
return nil, fmt.Errorf("ContentCipher is nil, Please call the InitiateMultipartUpload")
}
totalBytes, err := cos.GetReaderLen(r)
if err == nil {
// 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader需用户指定ContentLength
if opt != nil && opt.ContentLength == 0 && cos.IsLenReader(r) {
opt.ContentLength = totalBytes
}
}
cd := cryptoCtx.ContentCipher.GetCipherData().Clone()
cd.SeekIV(uint64(partNumber-1) * uint64(cryptoCtx.PartSize))
cc, err := cryptoCtx.ContentCipher.Clone(cd)
opt.ContentLength = cc.GetEncryptedLen(opt.ContentLength)
if err != nil {
return nil, err
}
reader, err := cc.EncryptContent(r)
if err != nil {
return nil, err
}
return s.ObjectService.UploadPart(ctx, name, uploadID, partNumber, reader, opt)
}
func (s *CryptoObjectService) CompleteMultipartUpload(ctx context.Context, name, uploadID string, opt *cos.CompleteMultipartUploadOptions) (*cos.CompleteMultipartUploadResult, *cos.Response, error) {
opt = cos.CloneCompleteMultipartUploadOptions(opt)
if opt.XOptionHeader == nil {
opt.XOptionHeader = &http.Header{}
}
opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
return s.ObjectService.CompleteMultipartUpload(ctx, name, uploadID, opt)
}
func (s *CryptoObjectService) CopyPart(ctx context.Context, name, uploadID string, partNumber int, sourceURL string, opt *cos.ObjectCopyPartOptions) (*cos.CopyPartResult, *cos.Response, error) {
return nil, nil, fmt.Errorf("CryptoObjectService doesn't support CopyPart")
}