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

4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package coscrypto
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "strconv"
  8. "git.ouxuan.net/tommy/cos-go-sdk-v5"
  9. )
  10. type CryptoContext struct {
  11. DataSize int64
  12. PartSize int64
  13. ContentCipher ContentCipher
  14. }
  15. func partSizeIsValid(partSize int64, alignLen int64) bool {
  16. if partSize%alignLen == 0 {
  17. return true
  18. }
  19. return false
  20. }
  21. func (s *CryptoObjectService) InitiateMultipartUpload(ctx context.Context, name string, opt *cos.InitiateMultipartUploadOptions, cryptoCtx *CryptoContext) (*cos.InitiateMultipartUploadResult, *cos.Response, error) {
  22. contentCipher, err := s.cryptoClient.ContentCipherBuilder.ContentCipher()
  23. if err != nil {
  24. return nil, nil, err
  25. }
  26. if !partSizeIsValid(cryptoCtx.PartSize, int64(contentCipher.GetAlignLen())) {
  27. return nil, nil, fmt.Errorf("PartSize is invalid, it should be %v aligned", contentCipher.GetAlignLen())
  28. }
  29. // 添加自定义头部
  30. cryptoCtx.ContentCipher = contentCipher
  31. opt = cos.CloneInitiateMultipartUploadOptions(opt)
  32. if opt.XOptionHeader == nil {
  33. opt.XOptionHeader = &http.Header{}
  34. }
  35. if opt.ContentMD5 != "" {
  36. opt.XOptionHeader.Add(COSClientSideEncryptionUnencryptedContentMD5, opt.ContentMD5)
  37. opt.ContentMD5 = ""
  38. }
  39. if cryptoCtx.DataSize > 0 {
  40. opt.XOptionHeader.Add(COSClientSideEncryptionDataSize, strconv.FormatInt(cryptoCtx.DataSize, 10))
  41. }
  42. opt.XOptionHeader.Add(COSClientSideEncryptionPartSize, strconv.FormatInt(cryptoCtx.PartSize, 10))
  43. opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
  44. addCryptoHeaders(opt.XOptionHeader, contentCipher.GetCipherData())
  45. return s.ObjectService.InitiateMultipartUpload(ctx, name, opt)
  46. }
  47. func (s *CryptoObjectService) UploadPart(ctx context.Context, name, uploadID string, partNumber int, r io.Reader, opt *cos.ObjectUploadPartOptions, cryptoCtx *CryptoContext) (*cos.Response, error) {
  48. if cryptoCtx.PartSize == 0 {
  49. return nil, fmt.Errorf("CryptoContext's PartSize is zero")
  50. }
  51. opt = cos.CloneObjectUploadPartOptions(opt)
  52. if opt.XOptionHeader == nil {
  53. opt.XOptionHeader = &http.Header{}
  54. }
  55. opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
  56. if cryptoCtx.ContentCipher == nil {
  57. return nil, fmt.Errorf("ContentCipher is nil, Please call the InitiateMultipartUpload")
  58. }
  59. totalBytes, err := cos.GetReaderLen(r)
  60. if err == nil {
  61. // 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader需用户指定ContentLength
  62. if opt != nil && opt.ContentLength == 0 && cos.IsLenReader(r) {
  63. opt.ContentLength = totalBytes
  64. }
  65. }
  66. cd := cryptoCtx.ContentCipher.GetCipherData().Clone()
  67. cd.SeekIV(uint64(partNumber-1) * uint64(cryptoCtx.PartSize))
  68. cc, err := cryptoCtx.ContentCipher.Clone(cd)
  69. opt.ContentLength = cc.GetEncryptedLen(opt.ContentLength)
  70. if err != nil {
  71. return nil, err
  72. }
  73. reader, err := cc.EncryptContent(r)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return s.ObjectService.UploadPart(ctx, name, uploadID, partNumber, reader, opt)
  78. }
  79. func (s *CryptoObjectService) CompleteMultipartUpload(ctx context.Context, name, uploadID string, opt *cos.CompleteMultipartUploadOptions) (*cos.CompleteMultipartUploadResult, *cos.Response, error) {
  80. opt = cos.CloneCompleteMultipartUploadOptions(opt)
  81. if opt.XOptionHeader == nil {
  82. opt.XOptionHeader = &http.Header{}
  83. }
  84. opt.XOptionHeader.Add(UserAgent, s.cryptoClient.userAgent)
  85. return s.ObjectService.CompleteMultipartUpload(ctx, name, uploadID, opt)
  86. }
  87. func (s *CryptoObjectService) CopyPart(ctx context.Context, name, uploadID string, partNumber int, sourceURL string, opt *cos.ObjectCopyPartOptions) (*cos.CopyPartResult, *cos.Response, error) {
  88. return nil, nil, fmt.Errorf("CryptoObjectService doesn't support CopyPart")
  89. }