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
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")
|
|
}
|