github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/strategy.go (about) 1 package s3crypto 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io/ioutil" 7 "net/http" 8 "strings" 9 10 "github.com/aavshr/aws-sdk-go/aws" 11 "github.com/aavshr/aws-sdk-go/aws/awserr" 12 "github.com/aavshr/aws-sdk-go/aws/request" 13 "github.com/aavshr/aws-sdk-go/service/s3" 14 ) 15 16 // SaveStrategy is how the data's metadata wants to be saved 17 type SaveStrategy interface { 18 Save(Envelope, *request.Request) error 19 } 20 21 // S3SaveStrategy will save the metadata to a separate instruction file in S3 22 type S3SaveStrategy struct { 23 Client *s3.S3 24 InstructionFileSuffix string 25 } 26 27 // Save will save the envelope contents to s3. 28 func (strat S3SaveStrategy) Save(env Envelope, req *request.Request) error { 29 input := req.Params.(*s3.PutObjectInput) 30 b, err := json.Marshal(env) 31 if err != nil { 32 return err 33 } 34 35 instInput := s3.PutObjectInput{ 36 Bucket: input.Bucket, 37 Body: bytes.NewReader(b), 38 } 39 40 if strat.InstructionFileSuffix == "" { 41 instInput.Key = aws.String(*input.Key + DefaultInstructionKeySuffix) 42 } else { 43 instInput.Key = aws.String(*input.Key + strat.InstructionFileSuffix) 44 } 45 46 _, err = strat.Client.PutObject(&instInput) 47 return err 48 } 49 50 // HeaderV2SaveStrategy will save the metadata of the crypto contents to the header of 51 // the object. 52 type HeaderV2SaveStrategy struct{} 53 54 // Save will save the envelope to the request's header. 55 func (strat HeaderV2SaveStrategy) Save(env Envelope, req *request.Request) error { 56 input := req.Params.(*s3.PutObjectInput) 57 if input.Metadata == nil { 58 input.Metadata = map[string]*string{} 59 } 60 61 input.Metadata[http.CanonicalHeaderKey(keyV2Header)] = &env.CipherKey 62 input.Metadata[http.CanonicalHeaderKey(ivHeader)] = &env.IV 63 input.Metadata[http.CanonicalHeaderKey(matDescHeader)] = &env.MatDesc 64 input.Metadata[http.CanonicalHeaderKey(wrapAlgorithmHeader)] = &env.WrapAlg 65 input.Metadata[http.CanonicalHeaderKey(cekAlgorithmHeader)] = &env.CEKAlg 66 input.Metadata[http.CanonicalHeaderKey(unencryptedContentLengthHeader)] = &env.UnencryptedContentLen 67 68 if len(env.TagLen) > 0 { 69 input.Metadata[http.CanonicalHeaderKey(tagLengthHeader)] = &env.TagLen 70 } 71 return nil 72 } 73 74 // LoadStrategy ... 75 type LoadStrategy interface { 76 Load(*request.Request) (Envelope, error) 77 } 78 79 // S3LoadStrategy will load the instruction file from s3 80 type S3LoadStrategy struct { 81 Client *s3.S3 82 InstructionFileSuffix string 83 } 84 85 // Load from a given instruction file suffix 86 func (load S3LoadStrategy) Load(req *request.Request) (Envelope, error) { 87 env := Envelope{} 88 if load.InstructionFileSuffix == "" { 89 load.InstructionFileSuffix = DefaultInstructionKeySuffix 90 } 91 92 input := req.Params.(*s3.GetObjectInput) 93 out, err := load.Client.GetObject(&s3.GetObjectInput{ 94 Key: aws.String(strings.Join([]string{*input.Key, load.InstructionFileSuffix}, "")), 95 Bucket: input.Bucket, 96 }) 97 if err != nil { 98 return env, err 99 } 100 101 b, err := ioutil.ReadAll(out.Body) 102 if err != nil { 103 return env, err 104 } 105 err = json.Unmarshal(b, &env) 106 return env, err 107 } 108 109 // HeaderV2LoadStrategy will load the envelope from the metadata 110 type HeaderV2LoadStrategy struct{} 111 112 // Load from a given object's header 113 func (load HeaderV2LoadStrategy) Load(req *request.Request) (Envelope, error) { 114 env := Envelope{} 115 env.CipherKey = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV2Header}, "-")) 116 env.IV = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, ivHeader}, "-")) 117 env.MatDesc = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, matDescHeader}, "-")) 118 env.WrapAlg = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, wrapAlgorithmHeader}, "-")) 119 env.CEKAlg = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, cekAlgorithmHeader}, "-")) 120 env.TagLen = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, tagLengthHeader}, "-")) 121 env.UnencryptedContentLen = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, unencryptedContentLengthHeader}, "-")) 122 return env, nil 123 } 124 125 type defaultV2LoadStrategy struct { 126 client *s3.S3 127 suffix string 128 } 129 130 func (load defaultV2LoadStrategy) Load(req *request.Request) (Envelope, error) { 131 if value := req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV2Header}, "-")); value != "" { 132 strat := HeaderV2LoadStrategy{} 133 return strat.Load(req) 134 } else if value = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV1Header}, "-")); value != "" { 135 return Envelope{}, awserr.New("V1NotSupportedError", "The AWS SDK for Go does not support version 1", nil) 136 } 137 138 strat := S3LoadStrategy{ 139 Client: load.client, 140 InstructionFileSuffix: load.suffix, 141 } 142 return strat.Load(req) 143 }