aws-sdk-s3 1.75.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aws-sdk-s3.rb +73 -0
  3. data/lib/aws-sdk-s3/bucket.rb +861 -0
  4. data/lib/aws-sdk-s3/bucket_acl.rb +277 -0
  5. data/lib/aws-sdk-s3/bucket_cors.rb +262 -0
  6. data/lib/aws-sdk-s3/bucket_lifecycle.rb +264 -0
  7. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +283 -0
  8. data/lib/aws-sdk-s3/bucket_logging.rb +251 -0
  9. data/lib/aws-sdk-s3/bucket_notification.rb +293 -0
  10. data/lib/aws-sdk-s3/bucket_policy.rb +242 -0
  11. data/lib/aws-sdk-s3/bucket_region_cache.rb +81 -0
  12. data/lib/aws-sdk-s3/bucket_request_payment.rb +236 -0
  13. data/lib/aws-sdk-s3/bucket_tagging.rb +251 -0
  14. data/lib/aws-sdk-s3/bucket_versioning.rb +312 -0
  15. data/lib/aws-sdk-s3/bucket_website.rb +292 -0
  16. data/lib/aws-sdk-s3/client.rb +11818 -0
  17. data/lib/aws-sdk-s3/client_api.rb +3014 -0
  18. data/lib/aws-sdk-s3/customizations.rb +34 -0
  19. data/lib/aws-sdk-s3/customizations/bucket.rb +162 -0
  20. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +44 -0
  21. data/lib/aws-sdk-s3/customizations/object.rb +389 -0
  22. data/lib/aws-sdk-s3/customizations/object_summary.rb +85 -0
  23. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +13 -0
  24. data/lib/aws-sdk-s3/encryption.rb +21 -0
  25. data/lib/aws-sdk-s3/encryption/client.rb +375 -0
  26. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +190 -0
  27. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +65 -0
  28. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +40 -0
  29. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +61 -0
  30. data/lib/aws-sdk-s3/encryption/errors.rb +15 -0
  31. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +58 -0
  32. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +36 -0
  33. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +71 -0
  34. data/lib/aws-sdk-s3/encryption/key_provider.rb +31 -0
  35. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +75 -0
  36. data/lib/aws-sdk-s3/encryption/materials.rb +60 -0
  37. data/lib/aws-sdk-s3/encryption/utils.rb +81 -0
  38. data/lib/aws-sdk-s3/encryptionV2/client.rb +388 -0
  39. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +198 -0
  40. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +103 -0
  41. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +38 -0
  42. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +66 -0
  43. data/lib/aws-sdk-s3/encryptionV2/errors.rb +13 -0
  44. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +56 -0
  45. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +35 -0
  46. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +71 -0
  47. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +29 -0
  48. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +99 -0
  49. data/lib/aws-sdk-s3/encryptionV2/materials.rb +58 -0
  50. data/lib/aws-sdk-s3/encryptionV2/utils.rb +116 -0
  51. data/lib/aws-sdk-s3/encryption_v2.rb +20 -0
  52. data/lib/aws-sdk-s3/errors.rb +115 -0
  53. data/lib/aws-sdk-s3/event_streams.rb +69 -0
  54. data/lib/aws-sdk-s3/file_downloader.rb +142 -0
  55. data/lib/aws-sdk-s3/file_part.rb +78 -0
  56. data/lib/aws-sdk-s3/file_uploader.rb +70 -0
  57. data/lib/aws-sdk-s3/legacy_signer.rb +189 -0
  58. data/lib/aws-sdk-s3/multipart_file_uploader.rb +227 -0
  59. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +173 -0
  60. data/lib/aws-sdk-s3/multipart_upload.rb +401 -0
  61. data/lib/aws-sdk-s3/multipart_upload_error.rb +18 -0
  62. data/lib/aws-sdk-s3/multipart_upload_part.rb +423 -0
  63. data/lib/aws-sdk-s3/object.rb +1422 -0
  64. data/lib/aws-sdk-s3/object_acl.rb +333 -0
  65. data/lib/aws-sdk-s3/object_copier.rb +101 -0
  66. data/lib/aws-sdk-s3/object_multipart_copier.rb +182 -0
  67. data/lib/aws-sdk-s3/object_summary.rb +1181 -0
  68. data/lib/aws-sdk-s3/object_version.rb +550 -0
  69. data/lib/aws-sdk-s3/plugins/accelerate.rb +87 -0
  70. data/lib/aws-sdk-s3/plugins/bucket_arn.rb +212 -0
  71. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +91 -0
  72. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +45 -0
  73. data/lib/aws-sdk-s3/plugins/dualstack.rb +74 -0
  74. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +28 -0
  75. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +25 -0
  76. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +55 -0
  77. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +62 -0
  78. data/lib/aws-sdk-s3/plugins/location_constraint.rb +35 -0
  79. data/lib/aws-sdk-s3/plugins/md5s.rb +84 -0
  80. data/lib/aws-sdk-s3/plugins/redirects.rb +45 -0
  81. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +30 -0
  82. data/lib/aws-sdk-s3/plugins/s3_signer.rb +222 -0
  83. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +70 -0
  84. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  85. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +97 -0
  86. data/lib/aws-sdk-s3/presigned_post.rb +686 -0
  87. data/lib/aws-sdk-s3/presigner.rb +253 -0
  88. data/lib/aws-sdk-s3/resource.rb +117 -0
  89. data/lib/aws-sdk-s3/types.rb +13154 -0
  90. data/lib/aws-sdk-s3/waiters.rb +243 -0
  91. metadata +184 -0
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module Encryption
8
+ # @api private
9
+ class DecryptHandler < Seahorse::Client::Handler
10
+
11
+ V1_ENVELOPE_KEYS = %w(
12
+ x-amz-key
13
+ x-amz-iv
14
+ x-amz-matdesc
15
+ )
16
+
17
+ V2_ENVELOPE_KEYS = %w(
18
+ x-amz-key-v2
19
+ x-amz-iv
20
+ x-amz-cek-alg
21
+ x-amz-wrap-alg
22
+ x-amz-matdesc
23
+ )
24
+
25
+ POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS + V2_ENVELOPE_KEYS).uniq
26
+
27
+ POSSIBLE_ENCRYPTION_FORMATS = %w(
28
+ AES/GCM/NoPadding
29
+ AES/CBC/PKCS5Padding
30
+ AES/CBC/PKCS7Padding
31
+ )
32
+
33
+ def call(context)
34
+ attach_http_event_listeners(context)
35
+ apply_cse_user_agent(context)
36
+ @handler.call(context)
37
+ end
38
+
39
+ private
40
+
41
+ def attach_http_event_listeners(context)
42
+
43
+ context.http_response.on_headers(200) do
44
+ cipher = decryption_cipher(context)
45
+ decrypter = body_contains_auth_tag?(context) ?
46
+ authenticated_decrypter(context, cipher) :
47
+ IODecrypter.new(cipher, context.http_response.body)
48
+ context.http_response.body = decrypter
49
+ end
50
+
51
+ context.http_response.on_success(200) do
52
+ decrypter = context.http_response.body
53
+ decrypter.finalize
54
+ decrypter.io.rewind if decrypter.io.respond_to?(:rewind)
55
+ context.http_response.body = decrypter.io
56
+ end
57
+
58
+ context.http_response.on_error do
59
+ if context.http_response.body.respond_to?(:io)
60
+ context.http_response.body = context.http_response.body.io
61
+ end
62
+ end
63
+ end
64
+
65
+ def decryption_cipher(context)
66
+ if envelope = get_encryption_envelope(context)
67
+ context[:encryption][:cipher_provider].decryption_cipher(envelope)
68
+ else
69
+ raise Errors::DecryptionError, "unable to locate encryption envelope"
70
+ end
71
+ end
72
+
73
+ def get_encryption_envelope(context)
74
+ if context[:encryption][:envelope_location] == :metadata
75
+ envelope_from_metadata(context) || envelope_from_instr_file(context)
76
+ else
77
+ envelope_from_instr_file(context) || envelope_from_metadata(context)
78
+ end
79
+ end
80
+
81
+ def envelope_from_metadata(context)
82
+ possible_envelope = {}
83
+ POSSIBLE_ENVELOPE_KEYS.each do |suffix|
84
+ if value = context.http_response.headers["x-amz-meta-#{suffix}"]
85
+ possible_envelope[suffix] = value
86
+ end
87
+ end
88
+ extract_envelope(possible_envelope)
89
+ end
90
+
91
+ def envelope_from_instr_file(context)
92
+ suffix = context[:encryption][:instruction_file_suffix]
93
+ possible_envelope = Json.load(context.client.get_object(
94
+ bucket: context.params[:bucket],
95
+ key: context.params[:key] + suffix
96
+ ).body.read)
97
+ extract_envelope(possible_envelope)
98
+ rescue S3::Errors::ServiceError, Json::ParseError
99
+ nil
100
+ end
101
+
102
+ def extract_envelope(hash)
103
+ return v1_envelope(hash) if hash.key?('x-amz-key')
104
+ return v2_envelope(hash) if hash.key?('x-amz-key-v2')
105
+ if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
106
+ msg = "unsupported envelope encryption version #{$1}"
107
+ raise Errors::DecryptionError, msg
108
+ else
109
+ nil # no envelope found
110
+ end
111
+ end
112
+
113
+ def v1_envelope(envelope)
114
+ envelope
115
+ end
116
+
117
+ def v2_envelope(envelope)
118
+ unless POSSIBLE_ENCRYPTION_FORMATS.include? envelope['x-amz-cek-alg']
119
+ alg = envelope['x-amz-cek-alg'].inspect
120
+ msg = "unsupported content encrypting key (cek) format: #{alg}"
121
+ raise Errors::DecryptionError, msg
122
+ end
123
+ unless envelope['x-amz-wrap-alg'] == 'kms'
124
+ # possible to support
125
+ # RSA/ECB/OAEPWithSHA-256AndMGF1Padding
126
+ alg = envelope['x-amz-wrap-alg'].inspect
127
+ msg = "unsupported key wrapping algorithm: #{alg}"
128
+ raise Errors::DecryptionError, msg
129
+ end
130
+ unless V2_ENVELOPE_KEYS.sort == envelope.keys.sort
131
+ msg = "incomplete v2 encryption envelope:\n"
132
+ msg += " expected: #{V2_ENVELOPE_KEYS.join(',')}\n"
133
+ msg += " got: #{envelope_keys.join(', ')}"
134
+ raise Errors::DecryptionError, msg
135
+ end
136
+ envelope
137
+ end
138
+
139
+ # When the x-amz-meta-x-amz-tag-len header is present, it indicates
140
+ # that the body of this object has a trailing auth tag. The header
141
+ # indicates the length of that tag.
142
+ #
143
+ # This method fetches the tag from the end of the object by
144
+ # making a GET Object w/range request. This auth tag is used
145
+ # to initialize the cipher, and the decrypter truncates the
146
+ # auth tag from the body when writing the final bytes.
147
+ def authenticated_decrypter(context, cipher)
148
+ if RUBY_VERSION.match(/1.9/)
149
+ raise "authenticated decryption not supported by OpeenSSL in Ruby version ~> 1.9"
150
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
151
+ end
152
+ http_resp = context.http_response
153
+ content_length = http_resp.headers['content-length'].to_i
154
+ auth_tag_length = http_resp.headers['x-amz-meta-x-amz-tag-len']
155
+ auth_tag_length = auth_tag_length.to_i / 8
156
+
157
+ auth_tag = context.client.get_object(
158
+ bucket: context.params[:bucket],
159
+ key: context.params[:key],
160
+ range: "bytes=-#{auth_tag_length}"
161
+ ).body.read
162
+
163
+ cipher.auth_tag = auth_tag
164
+ cipher.auth_data = ''
165
+
166
+ # The encrypted object contains both the cipher text
167
+ # plus a trailing auth tag. This decrypter will the body
168
+ # expect for the trailing auth tag.
169
+ IOAuthDecrypter.new(
170
+ io: http_resp.body,
171
+ encrypted_content_length: content_length - auth_tag_length,
172
+ cipher: cipher)
173
+ end
174
+
175
+ def body_contains_auth_tag?(context)
176
+ context.http_response.headers['x-amz-meta-x-amz-tag-len']
177
+ end
178
+
179
+ def apply_cse_user_agent(context)
180
+ if context.config.user_agent_suffix.nil?
181
+ context.config.user_agent_suffix = 'CSE_V1'
182
+ elsif !context.config.user_agent_suffix.include? 'CSE_V1'
183
+ context.config.user_agent_suffix += ' CSE_V1'
184
+ end
185
+ end
186
+
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module Encryption
8
+ # @api private
9
+ class DefaultCipherProvider
10
+
11
+ def initialize(options = {})
12
+ @key_provider = options[:key_provider]
13
+ end
14
+
15
+ # @return [Array<Hash,Cipher>] Creates an returns a new encryption
16
+ # envelope and encryption cipher.
17
+ def encryption_cipher
18
+ cipher = Utils.aes_encryption_cipher(:CBC)
19
+ envelope = {
20
+ 'x-amz-key' => encode64(encrypt(envelope_key(cipher))),
21
+ 'x-amz-iv' => encode64(envelope_iv(cipher)),
22
+ 'x-amz-matdesc' => materials_description,
23
+ }
24
+ [envelope, cipher]
25
+ end
26
+
27
+ # @return [Cipher] Given an encryption envelope, returns a
28
+ # decryption cipher.
29
+ def decryption_cipher(envelope)
30
+ master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
31
+ key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
32
+ iv = decode64(envelope['x-amz-iv'])
33
+ Utils.aes_decryption_cipher(:CBC, key, iv)
34
+ end
35
+
36
+ private
37
+
38
+ def envelope_key(cipher)
39
+ cipher.key = cipher.random_key
40
+ end
41
+
42
+ def envelope_iv(cipher)
43
+ cipher.iv = cipher.random_iv
44
+ end
45
+
46
+ def encrypt(data)
47
+ Utils.encrypt(@key_provider.encryption_materials.key, data)
48
+ end
49
+
50
+ def materials_description
51
+ @key_provider.encryption_materials.description
52
+ end
53
+
54
+ def encode64(str)
55
+ Base64.encode64(str).split("\n") * ""
56
+ end
57
+
58
+ def decode64(str)
59
+ Base64.decode64(str)
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Encryption
6
+
7
+ # The default key provider is constructed with a single key
8
+ # that is used for both encryption and decryption, ignoring
9
+ # the possible per-object envelope encryption materials description.
10
+ # @api private
11
+ class DefaultKeyProvider
12
+
13
+ include KeyProvider
14
+
15
+ # @option options [required, OpenSSL::PKey::RSA, String] :encryption_key
16
+ # The master key to use for encrypting objects.
17
+ # @option options [String<JSON>] :materials_description ('{}')
18
+ # A description of the encryption key.
19
+ def initialize(options = {})
20
+ @encryption_materials = Materials.new(
21
+ key: options[:encryption_key],
22
+ description: options[:materials_description] || '{}'
23
+ )
24
+ end
25
+
26
+ # @return [Materials]
27
+ def encryption_materials
28
+ @encryption_materials
29
+ end
30
+
31
+ # @param [String<JSON>] materials_description
32
+ # @return Returns the key given in the constructor.
33
+ def key_for(materials_description)
34
+ @encryption_materials.key
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Aws
6
+ module S3
7
+ module Encryption
8
+ # @api private
9
+ class EncryptHandler < Seahorse::Client::Handler
10
+
11
+ def call(context)
12
+ envelope, cipher = context[:encryption][:cipher_provider].encryption_cipher
13
+ apply_encryption_envelope(context, envelope, cipher)
14
+ apply_encryption_cipher(context, cipher)
15
+ apply_cse_user_agent(context)
16
+ @handler.call(context)
17
+ end
18
+
19
+ private
20
+
21
+ def apply_encryption_envelope(context, envelope, cipher)
22
+ context[:encryption][:cipher] = cipher
23
+ if context[:encryption][:envelope_location] == :metadata
24
+ context.params[:metadata] ||= {}
25
+ context.params[:metadata].update(envelope)
26
+ else # :instruction_file
27
+ suffix = context[:encryption][:instruction_file_suffix]
28
+ context.client.put_object(
29
+ bucket: context.params[:bucket],
30
+ key: context.params[:key] + suffix,
31
+ body: Json.dump(envelope)
32
+ )
33
+ end
34
+ end
35
+
36
+ def apply_encryption_cipher(context, cipher)
37
+ io = context.params[:body] || ''
38
+ io = StringIO.new(io) if String === io
39
+ context.params[:body] = IOEncrypter.new(cipher, io)
40
+ context.params[:metadata] ||= {}
41
+ context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
42
+ if md5 = context.params.delete(:content_md5)
43
+ context.params[:metadata]['x-amz-unencrypted-content-md5'] = md5
44
+ end
45
+ context.http_response.on_headers do
46
+ context.params[:body].close
47
+ end
48
+ end
49
+
50
+ def apply_cse_user_agent(context)
51
+ if context.config.user_agent_suffix.nil?
52
+ context.config.user_agent_suffix = 'CSE_V1'
53
+ elsif !context.config.user_agent_suffix.include? 'CSE_V1'
54
+ context.config.user_agent_suffix += ' CSE_V1'
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Encryption
6
+ module Errors
7
+
8
+ class DecryptionError < RuntimeError; end
9
+
10
+ class EncryptionError < RuntimeError; end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Encryption
6
+ # @api private
7
+ class IOAuthDecrypter
8
+
9
+ # @option options [required, IO#write] :io
10
+ # An IO-like object that responds to {#write}.
11
+ # @option options [required, Integer] :encrypted_content_length
12
+ # The number of bytes to decrypt from the `:io` object.
13
+ # This should be the total size of `:io` minus the length of
14
+ # the cipher auth tag.
15
+ # @option options [required, OpenSSL::Cipher] :cipher An initialized
16
+ # cipher that can be used to decrypt the bytes as they are
17
+ # written to the `:io` object. The cipher should already have
18
+ # its `#auth_tag` set.
19
+ def initialize(options = {})
20
+ @decrypter = IODecrypter.new(options[:cipher], options[:io])
21
+ @max_bytes = options[:encrypted_content_length]
22
+ @bytes_written = 0
23
+ end
24
+
25
+ def write(chunk)
26
+ chunk = truncate_chunk(chunk)
27
+ if chunk.bytesize > 0
28
+ @bytes_written += chunk.bytesize
29
+ @decrypter.write(chunk)
30
+ end
31
+ end
32
+
33
+ def finalize
34
+ @decrypter.finalize
35
+ end
36
+
37
+ def io
38
+ @decrypter.io
39
+ end
40
+
41
+ private
42
+
43
+ def truncate_chunk(chunk)
44
+ if chunk.bytesize + @bytes_written <= @max_bytes
45
+ chunk
46
+ elsif @bytes_written < @max_bytes
47
+ chunk[0..(@max_bytes - @bytes_written - 1)]
48
+ else
49
+ # If the tag was sent over after the full body has been read,
50
+ # we don't want to accidentally append it.
51
+ ""
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Encryption
6
+ # @api private
7
+ class IODecrypter
8
+
9
+ # @param [OpenSSL::Cipher] cipher
10
+ # @param [IO#write] io An IO-like object that responds to `#write`.
11
+ def initialize(cipher, io)
12
+ @cipher = cipher.clone
13
+ # Ensure that IO is reset between retries
14
+ @io = io.tap { |io| io.truncate(0) if io.respond_to?(:truncate) }
15
+ end
16
+
17
+ # @return [#write]
18
+ attr_reader :io
19
+
20
+ def write(chunk)
21
+ # decrypt and write
22
+ @io.write(@cipher.update(chunk))
23
+ end
24
+
25
+ def finalize
26
+ @io.write(@cipher.final)
27
+ end
28
+
29
+ def size
30
+ @io.size
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end