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  }