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,198 @@
1
+ require 'base64'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ # @api private
7
+ class DecryptHandler < Seahorse::Client::Handler
8
+
9
+ V1_ENVELOPE_KEYS = %w(
10
+ x-amz-key
11
+ x-amz-iv
12
+ x-amz-matdesc
13
+ )
14
+
15
+ V2_ENVELOPE_KEYS = %w(
16
+ x-amz-key-v2
17
+ x-amz-iv
18
+ x-amz-cek-alg
19
+ x-amz-wrap-alg
20
+ x-amz-matdesc
21
+ )
22
+
23
+ V2_OPTIONAL_KEYS = %w(x-amz-tag-len)
24
+
25
+ POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS +
26
+ V2_ENVELOPE_KEYS + V2_OPTIONAL_KEYS).uniq
27
+
28
+ POSSIBLE_WRAPPING_FORMATS = %w(
29
+ AES/GCM
30
+ kms
31
+ kms+context
32
+ RSA-OAEP-SHA1
33
+ )
34
+
35
+ POSSIBLE_ENCRYPTION_FORMATS = %w(
36
+ AES/GCM/NoPadding
37
+ AES/CBC/PKCS5Padding
38
+ AES/CBC/PKCS7Padding
39
+ )
40
+
41
+ def call(context)
42
+ attach_http_event_listeners(context)
43
+ apply_cse_user_agent(context)
44
+ @handler.call(context)
45
+ end
46
+
47
+ private
48
+
49
+ def attach_http_event_listeners(context)
50
+
51
+ context.http_response.on_headers(200) do
52
+ cipher, envelope = decryption_cipher(context)
53
+ decrypter = body_contains_auth_tag?(envelope) ?
54
+ authenticated_decrypter(context, cipher, envelope) :
55
+ IODecrypter.new(cipher, context.http_response.body)
56
+ context.http_response.body = decrypter
57
+ end
58
+
59
+ context.http_response.on_success(200) do
60
+ decrypter = context.http_response.body
61
+ decrypter.finalize
62
+ decrypter.io.rewind if decrypter.io.respond_to?(:rewind)
63
+ context.http_response.body = decrypter.io
64
+ end
65
+
66
+ context.http_response.on_error do
67
+ if context.http_response.body.respond_to?(:io)
68
+ context.http_response.body = context.http_response.body.io
69
+ end
70
+ end
71
+ end
72
+
73
+ def decryption_cipher(context)
74
+ if envelope = get_encryption_envelope(context)
75
+ cipher = context[:encryption][:cipher_provider]
76
+ .decryption_cipher(
77
+ envelope,
78
+ kms_encryption_context: context[:encryption][:kms_encryption_context]
79
+ )
80
+ [cipher, envelope]
81
+ else
82
+ raise Errors::DecryptionError, "unable to locate encryption envelope"
83
+ end
84
+ end
85
+
86
+ def get_encryption_envelope(context)
87
+ if context[:encryption][:envelope_location] == :metadata
88
+ envelope_from_metadata(context) || envelope_from_instr_file(context)
89
+ else
90
+ envelope_from_instr_file(context) || envelope_from_metadata(context)
91
+ end
92
+ end
93
+
94
+ def envelope_from_metadata(context)
95
+ possible_envelope = {}
96
+ POSSIBLE_ENVELOPE_KEYS.each do |suffix|
97
+ if value = context.http_response.headers["x-amz-meta-#{suffix}"]
98
+ possible_envelope[suffix] = value
99
+ end
100
+ end
101
+ extract_envelope(possible_envelope)
102
+ end
103
+
104
+ def envelope_from_instr_file(context)
105
+ suffix = context[:encryption][:instruction_file_suffix]
106
+ possible_envelope = Json.load(context.client.get_object(
107
+ bucket: context.params[:bucket],
108
+ key: context.params[:key] + suffix
109
+ ).body.read)
110
+ extract_envelope(possible_envelope)
111
+ rescue S3::Errors::ServiceError, Json::ParseError
112
+ nil
113
+ end
114
+
115
+ def extract_envelope(hash)
116
+ return nil unless hash
117
+ return v1_envelope(hash) if hash.key?('x-amz-key')
118
+ return v2_envelope(hash) if hash.key?('x-amz-key-v2')
119
+ if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
120
+ msg = "unsupported envelope encryption version #{$1}"
121
+ raise Errors::DecryptionError, msg
122
+ end
123
+ end
124
+
125
+ def v1_envelope(envelope)
126
+ envelope
127
+ end
128
+
129
+ def v2_envelope(envelope)
130
+ unless POSSIBLE_ENCRYPTION_FORMATS.include? envelope['x-amz-cek-alg']
131
+ alg = envelope['x-amz-cek-alg'].inspect
132
+ msg = "unsupported content encrypting key (cek) format: #{alg}"
133
+ raise Errors::DecryptionError, msg
134
+ end
135
+ unless POSSIBLE_WRAPPING_FORMATS.include? envelope['x-amz-wrap-alg']
136
+ alg = envelope['x-amz-wrap-alg'].inspect
137
+ msg = "unsupported key wrapping algorithm: #{alg}"
138
+ raise Errors::DecryptionError, msg
139
+ end
140
+ unless (missing_keys = V2_ENVELOPE_KEYS - envelope.keys).empty?
141
+ msg = "incomplete v2 encryption envelope:\n"
142
+ msg += " missing: #{missing_keys.join(',')}\n"
143
+ raise Errors::DecryptionError, msg
144
+ end
145
+ envelope
146
+ end
147
+
148
+ # When the x-amz-meta-x-amz-tag-len header is present, it indicates
149
+ # that the body of this object has a trailing auth tag. The header
150
+ # indicates the length of that tag.
151
+ #
152
+ # This method fetches the tag from the end of the object by
153
+ # making a GET Object w/range request. This auth tag is used
154
+ # to initialize the cipher, and the decrypter truncates the
155
+ # auth tag from the body when writing the final bytes.
156
+ def authenticated_decrypter(context, cipher, envelope)
157
+ if RUBY_VERSION.match(/1.9/)
158
+ raise "authenticated decryption not supported by OpenSSL in Ruby version ~> 1.9"
159
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
160
+ end
161
+ http_resp = context.http_response
162
+ content_length = http_resp.headers['content-length'].to_i
163
+ auth_tag_length = envelope['x-amz-tag-len']
164
+ auth_tag_length = auth_tag_length.to_i / 8
165
+
166
+ auth_tag = context.client.get_object(
167
+ bucket: context.params[:bucket],
168
+ key: context.params[:key],
169
+ range: "bytes=-#{auth_tag_length}"
170
+ ).body.read
171
+
172
+ cipher.auth_tag = auth_tag
173
+ cipher.auth_data = ''
174
+
175
+ # The encrypted object contains both the cipher text
176
+ # plus a trailing auth tag.
177
+ IOAuthDecrypter.new(
178
+ io: http_resp.body,
179
+ encrypted_content_length: content_length - auth_tag_length,
180
+ cipher: cipher)
181
+ end
182
+
183
+ def body_contains_auth_tag?(envelope)
184
+ envelope.include? 'x-amz-tag-len'
185
+ end
186
+
187
+ def apply_cse_user_agent(context)
188
+ if context.config.user_agent_suffix.nil?
189
+ context.config.user_agent_suffix = 'CSE_V2'
190
+ elsif !context.config.user_agent_suffix.include? 'CSE_V2'
191
+ context.config.user_agent_suffix += ' CSE_V2'
192
+ end
193
+ end
194
+
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,103 @@
1
+ require 'base64'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ # @api private
7
+ class DefaultCipherProvider
8
+
9
+ def initialize(options = {})
10
+ @key_provider = options[:key_provider]
11
+ end
12
+
13
+ # @return [Array<Hash,Cipher>] Creates an returns a new encryption
14
+ # envelope and encryption cipher.
15
+ def encryption_cipher(options = {})
16
+ cipher = Utils.aes_encryption_cipher(:GCM)
17
+ cek_alg = 'AES/GCM/NoPadding'
18
+ if @key_provider.encryption_materials.key.is_a? OpenSSL::PKey::RSA
19
+ wrap_alg = 'RSA-OAEP-SHA1'
20
+ enc_key = encode64(encrypt_rsa(envelope_key(cipher), cek_alg))
21
+ else
22
+ wrap_alg = 'AES/GCM'
23
+ enc_key = encode64(encrypt_aes_gcm(envelope_key(cipher), cek_alg))
24
+ end
25
+ envelope = {
26
+ 'x-amz-key-v2' => enc_key,
27
+ 'x-amz-cek-alg' => cek_alg,
28
+ 'x-amz-tag-len' => 16 * 8,
29
+ 'x-amz-wrap-alg' => wrap_alg,
30
+ 'x-amz-iv' => encode64(envelope_iv(cipher)),
31
+ 'x-amz-matdesc' => materials_description,
32
+ }
33
+ cipher.auth_data = '' # auth_data must be set after key and iv
34
+ [envelope, cipher]
35
+ end
36
+
37
+ # @return [Cipher] Given an encryption envelope, returns a
38
+ # decryption cipher.
39
+ def decryption_cipher(envelope, options = {})
40
+ master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
41
+ if envelope.key? 'x-amz-key'
42
+ # Support for decryption of legacy objects
43
+ key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
44
+ iv = decode64(envelope['x-amz-iv'])
45
+ Utils.aes_decryption_cipher(:CBC, key, iv)
46
+ else
47
+ if envelope['x-amz-cek-alg'] != 'AES/GCM/NoPadding'
48
+ raise ArgumentError, 'Unsupported cek-alg: ' \
49
+ "#{envelope['x-amz-cek-alg']}"
50
+ end
51
+ key =
52
+ case envelope['x-amz-wrap-alg']
53
+ when 'AES/GCM'
54
+ Utils.decrypt_aes_gcm(master_key,
55
+ decode64(envelope['x-amz-key-v2']),
56
+ envelope['x-amz-cek-alg'])
57
+ when 'RSA-OAEP-SHA1'
58
+ key, cek_alg = Utils.decrypt_rsa(master_key, decode64(envelope['x-amz-key-v2']))
59
+ raise Errors::DecryptionError unless cek_alg == envelope['x-amz-cek-alg']
60
+ key
61
+ else
62
+ raise ArgumentError, 'Unsupported wrap-alg: ' \
63
+ "#{envelope['x-amz-wrap-alg']}"
64
+ end
65
+ iv = decode64(envelope['x-amz-iv'])
66
+ Utils.aes_decryption_cipher(:GCM, key, iv)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def envelope_key(cipher)
73
+ cipher.key = cipher.random_key
74
+ end
75
+
76
+ def envelope_iv(cipher)
77
+ cipher.iv = cipher.random_iv
78
+ end
79
+
80
+ def encrypt_aes_gcm(data, auth_data)
81
+ Utils.encrypt_aes_gcm(@key_provider.encryption_materials.key, data, auth_data)
82
+ end
83
+
84
+ def encrypt_rsa(data, auth_data)
85
+ Utils.encrypt_rsa(@key_provider.encryption_materials.key, data, auth_data)
86
+ end
87
+
88
+ def materials_description
89
+ @key_provider.encryption_materials.description
90
+ end
91
+
92
+ def encode64(str)
93
+ Base64.encode64(str).split("\n") * ''
94
+ end
95
+
96
+ def decode64(str)
97
+ Base64.decode64(str)
98
+ end
99
+
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,38 @@
1
+ module Aws
2
+ module S3
3
+ module EncryptionV2
4
+
5
+ # The default key provider is constructed with a single key
6
+ # that is used for both encryption and decryption, ignoring
7
+ # the possible per-object envelope encryption materials description.
8
+ # @api private
9
+ class DefaultKeyProvider
10
+
11
+ include KeyProvider
12
+
13
+ # @option options [required, OpenSSL::PKey::RSA, String] :encryption_key
14
+ # The master key to use for encrypting objects.
15
+ # @option options [String<JSON>] :materials_description ('{}')
16
+ # A description of the encryption key.
17
+ def initialize(options = {})
18
+ @encryption_materials = Materials.new(
19
+ key: options[:encryption_key],
20
+ description: options[:materials_description] || '{}'
21
+ )
22
+ end
23
+
24
+ # @return [Materials]
25
+ def encryption_materials
26
+ @encryption_materials
27
+ end
28
+
29
+ # @param [String<JSON>] materials_description
30
+ # @return Returns the key given in the constructor.
31
+ def key_for(materials_description)
32
+ @encryption_materials.key
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,66 @@
1
+ require 'base64'
2
+
3
+ module Aws
4
+ module S3
5
+ module EncryptionV2
6
+ # @api private
7
+ class EncryptHandler < Seahorse::Client::Handler
8
+
9
+ def call(context)
10
+ if RUBY_VERSION.match(/1.9/)
11
+ raise "authenticated encryption not supported by OpenSSL in Ruby version ~> 1.9"
12
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
13
+ end
14
+ envelope, cipher = context[:encryption][:cipher_provider]
15
+ .encryption_cipher(
16
+ kms_encryption_context: context[:encryption][:kms_encryption_context]
17
+ )
18
+ context[:encryption][:cipher] = cipher
19
+ apply_encryption_envelope(context, envelope)
20
+ apply_encryption_cipher(context, cipher)
21
+ apply_cse_user_agent(context)
22
+ @handler.call(context)
23
+ end
24
+
25
+ private
26
+
27
+ def apply_encryption_envelope(context, envelope)
28
+ if context[:encryption][:envelope_location] == :instruction_file
29
+ suffix = context[:encryption][:instruction_file_suffix]
30
+ context.client.put_object(
31
+ bucket: context.params[:bucket],
32
+ key: context.params[:key] + suffix,
33
+ body: Json.dump(envelope)
34
+ )
35
+ else # :metadata
36
+ context.params[:metadata] ||= {}
37
+ context.params[:metadata].update(envelope)
38
+ end
39
+ end
40
+
41
+ def apply_encryption_cipher(context, cipher)
42
+ io = context.params[:body] || ''
43
+ io = StringIO.new(io) if io.is_a? String
44
+ context.params[:body] = IOEncrypter.new(cipher, io)
45
+ context.params[:metadata] ||= {}
46
+ context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
47
+ if context.params.delete(:content_md5)
48
+ raise ArgumentError, 'content_md5 is not supported'
49
+ end
50
+ context.http_response.on_headers do
51
+ context.params[:body].close
52
+ end
53
+ end
54
+
55
+ def apply_cse_user_agent(context)
56
+ if context.config.user_agent_suffix.nil?
57
+ context.config.user_agent_suffix = 'CSE_V2'
58
+ elsif !context.config.user_agent_suffix.include? 'CSE_V2'
59
+ context.config.user_agent_suffix += ' CSE_V2'
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,13 @@
1
+ module Aws
2
+ module S3
3
+ module EncryptionV2
4
+ module Errors
5
+
6
+ class DecryptionError < RuntimeError; end
7
+
8
+ class EncryptionError < RuntimeError; end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ module Aws
2
+ module S3
3
+ module EncryptionV2
4
+ # @api private
5
+ class IOAuthDecrypter
6
+
7
+ # @option options [required, IO#write] :io
8
+ # An IO-like object that responds to {#write}.
9
+ # @option options [required, Integer] :encrypted_content_length
10
+ # The number of bytes to decrypt from the `:io` object.
11
+ # This should be the total size of `:io` minus the length of
12
+ # the cipher auth tag.
13
+ # @option options [required, OpenSSL::Cipher] :cipher An initialized
14
+ # cipher that can be used to decrypt the bytes as they are
15
+ # written to the `:io` object. The cipher should already have
16
+ # its `#auth_tag` set.
17
+ def initialize(options = {})
18
+ @decrypter = IODecrypter.new(options[:cipher], options[:io])
19
+ @max_bytes = options[:encrypted_content_length]
20
+ @bytes_written = 0
21
+ end
22
+
23
+ def write(chunk)
24
+ chunk = truncate_chunk(chunk)
25
+ if chunk.bytesize > 0
26
+ @bytes_written += chunk.bytesize
27
+ @decrypter.write(chunk)
28
+ end
29
+ end
30
+
31
+ def finalize
32
+ @decrypter.finalize
33
+ end
34
+
35
+ def io
36
+ @decrypter.io
37
+ end
38
+
39
+ private
40
+
41
+ def truncate_chunk(chunk)
42
+ if chunk.bytesize + @bytes_written <= @max_bytes
43
+ chunk
44
+ elsif @bytes_written < @max_bytes
45
+ chunk[0..(@max_bytes - @bytes_written - 1)]
46
+ else
47
+ # If the tag was sent over after the full body has been read,
48
+ # we don't want to accidentally append it.
49
+ ""
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end