| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package s3crypto
- import (
- "bytes"
- "encoding/json"
- "io/ioutil"
- "net/http"
- "strings"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/awserr"
- "github.com/aws/aws-sdk-go/aws/request"
- "github.com/aws/aws-sdk-go/service/s3"
- )
- // SaveStrategy is how the data's metadata wants to be saved
- type SaveStrategy interface {
- Save(Envelope, *request.Request) error
- }
- // S3SaveStrategy will save the metadata to a separate instruction file in S3
- type S3SaveStrategy struct {
- Client *s3.S3
- InstructionFileSuffix string
- }
- // Save will save the envelope contents to s3.
- func (strat S3SaveStrategy) Save(env Envelope, req *request.Request) error {
- input := req.Params.(*s3.PutObjectInput)
- b, err := json.Marshal(env)
- if err != nil {
- return err
- }
- instInput := s3.PutObjectInput{
- Bucket: input.Bucket,
- Body: bytes.NewReader(b),
- }
- if strat.InstructionFileSuffix == "" {
- instInput.Key = aws.String(*input.Key + DefaultInstructionKeySuffix)
- } else {
- instInput.Key = aws.String(*input.Key + strat.InstructionFileSuffix)
- }
- _, err = strat.Client.PutObject(&instInput)
- return err
- }
- // HeaderV2SaveStrategy will save the metadata of the crypto contents to the header of
- // the object.
- type HeaderV2SaveStrategy struct{}
- // Save will save the envelope to the request's header.
- func (strat HeaderV2SaveStrategy) Save(env Envelope, req *request.Request) error {
- input := req.Params.(*s3.PutObjectInput)
- if input.Metadata == nil {
- input.Metadata = map[string]*string{}
- }
- input.Metadata[http.CanonicalHeaderKey(keyV2Header)] = &env.CipherKey
- input.Metadata[http.CanonicalHeaderKey(ivHeader)] = &env.IV
- input.Metadata[http.CanonicalHeaderKey(matDescHeader)] = &env.MatDesc
- input.Metadata[http.CanonicalHeaderKey(wrapAlgorithmHeader)] = &env.WrapAlg
- input.Metadata[http.CanonicalHeaderKey(cekAlgorithmHeader)] = &env.CEKAlg
- input.Metadata[http.CanonicalHeaderKey(tagLengthHeader)] = &env.TagLen
- input.Metadata[http.CanonicalHeaderKey(unencryptedMD5Header)] = &env.UnencryptedMD5
- input.Metadata[http.CanonicalHeaderKey(unencryptedContentLengthHeader)] = &env.UnencryptedContentLen
- return nil
- }
- // LoadStrategy ...
- type LoadStrategy interface {
- Load(*request.Request) (Envelope, error)
- }
- // S3LoadStrategy will load the instruction file from s3
- type S3LoadStrategy struct {
- Client *s3.S3
- InstructionFileSuffix string
- }
- // Load from a given instruction file suffix
- func (load S3LoadStrategy) Load(req *request.Request) (Envelope, error) {
- env := Envelope{}
- if load.InstructionFileSuffix == "" {
- load.InstructionFileSuffix = DefaultInstructionKeySuffix
- }
- input := req.Params.(*s3.GetObjectInput)
- out, err := load.Client.GetObject(&s3.GetObjectInput{
- Key: aws.String(strings.Join([]string{*input.Key, load.InstructionFileSuffix}, "")),
- Bucket: input.Bucket,
- })
- if err != nil {
- return env, err
- }
- b, err := ioutil.ReadAll(out.Body)
- if err != nil {
- return env, err
- }
- err = json.Unmarshal(b, &env)
- return env, err
- }
- // HeaderV2LoadStrategy will load the envelope from the metadata
- type HeaderV2LoadStrategy struct{}
- // Load from a given object's header
- func (load HeaderV2LoadStrategy) Load(req *request.Request) (Envelope, error) {
- env := Envelope{}
- env.CipherKey = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV2Header}, "-"))
- env.IV = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, ivHeader}, "-"))
- env.MatDesc = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, matDescHeader}, "-"))
- env.WrapAlg = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, wrapAlgorithmHeader}, "-"))
- env.CEKAlg = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, cekAlgorithmHeader}, "-"))
- env.TagLen = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, tagLengthHeader}, "-"))
- env.UnencryptedMD5 = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, unencryptedMD5Header}, "-"))
- env.UnencryptedContentLen = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, unencryptedContentLengthHeader}, "-"))
- return env, nil
- }
- type defaultV2LoadStrategy struct {
- client *s3.S3
- suffix string
- }
- func (load defaultV2LoadStrategy) Load(req *request.Request) (Envelope, error) {
- if value := req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV2Header}, "-")); value != "" {
- strat := HeaderV2LoadStrategy{}
- return strat.Load(req)
- } else if value = req.HTTPResponse.Header.Get(strings.Join([]string{metaHeader, keyV1Header}, "-")); value != "" {
- return Envelope{}, awserr.New("V1NotSupportedError", "The AWS SDK for Go does not support version 1", nil)
- }
- strat := S3LoadStrategy{
- Client: load.client,
- InstructionFileSuffix: load.suffix,
- }
- return strat.Load(req)
- }
|