aws-sdk-s3 1.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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