aws-sdk-resources 2.11.549
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.
- checksums.yaml +7 -0
- data/lib/aws-sdk-resources.rb +91 -0
- data/lib/aws-sdk-resources/batch.rb +143 -0
- data/lib/aws-sdk-resources/builder.rb +85 -0
- data/lib/aws-sdk-resources/builder_sources.rb +105 -0
- data/lib/aws-sdk-resources/collection.rb +107 -0
- data/lib/aws-sdk-resources/definition.rb +331 -0
- data/lib/aws-sdk-resources/documenter.rb +70 -0
- data/lib/aws-sdk-resources/documenter/base_operation_documenter.rb +279 -0
- data/lib/aws-sdk-resources/documenter/data_operation_documenter.rb +25 -0
- data/lib/aws-sdk-resources/documenter/has_many_operation_documenter.rb +69 -0
- data/lib/aws-sdk-resources/documenter/has_operation_documenter.rb +66 -0
- data/lib/aws-sdk-resources/documenter/operation_documenter.rb +20 -0
- data/lib/aws-sdk-resources/documenter/resource_operation_documenter.rb +53 -0
- data/lib/aws-sdk-resources/documenter/waiter_operation_documenter.rb +77 -0
- data/lib/aws-sdk-resources/errors.rb +15 -0
- data/lib/aws-sdk-resources/operation_methods.rb +83 -0
- data/lib/aws-sdk-resources/operations.rb +280 -0
- data/lib/aws-sdk-resources/options.rb +17 -0
- data/lib/aws-sdk-resources/request.rb +39 -0
- data/lib/aws-sdk-resources/request_params.rb +140 -0
- data/lib/aws-sdk-resources/resource.rb +243 -0
- data/lib/aws-sdk-resources/services/ec2.rb +21 -0
- data/lib/aws-sdk-resources/services/ec2/instance.rb +29 -0
- data/lib/aws-sdk-resources/services/iam.rb +19 -0
- data/lib/aws-sdk-resources/services/s3.rb +20 -0
- data/lib/aws-sdk-resources/services/s3/bucket.rb +131 -0
- data/lib/aws-sdk-resources/services/s3/encryption.rb +21 -0
- data/lib/aws-sdk-resources/services/s3/encryption/client.rb +369 -0
- data/lib/aws-sdk-resources/services/s3/encryption/decrypt_handler.rb +174 -0
- data/lib/aws-sdk-resources/services/s3/encryption/default_cipher_provider.rb +63 -0
- data/lib/aws-sdk-resources/services/s3/encryption/default_key_provider.rb +38 -0
- data/lib/aws-sdk-resources/services/s3/encryption/encrypt_handler.rb +50 -0
- data/lib/aws-sdk-resources/services/s3/encryption/errors.rb +13 -0
- data/lib/aws-sdk-resources/services/s3/encryption/io_auth_decrypter.rb +56 -0
- data/lib/aws-sdk-resources/services/s3/encryption/io_decrypter.rb +29 -0
- data/lib/aws-sdk-resources/services/s3/encryption/io_encrypter.rb +69 -0
- data/lib/aws-sdk-resources/services/s3/encryption/key_provider.rb +29 -0
- data/lib/aws-sdk-resources/services/s3/encryption/kms_cipher_provider.rb +71 -0
- data/lib/aws-sdk-resources/services/s3/encryption/materials.rb +58 -0
- data/lib/aws-sdk-resources/services/s3/encryption/utils.rb +79 -0
- data/lib/aws-sdk-resources/services/s3/file_downloader.rb +169 -0
- data/lib/aws-sdk-resources/services/s3/file_part.rb +75 -0
- data/lib/aws-sdk-resources/services/s3/file_uploader.rb +58 -0
- data/lib/aws-sdk-resources/services/s3/multipart_file_uploader.rb +187 -0
- data/lib/aws-sdk-resources/services/s3/multipart_upload.rb +42 -0
- data/lib/aws-sdk-resources/services/s3/multipart_upload_error.rb +16 -0
- data/lib/aws-sdk-resources/services/s3/object.rb +290 -0
- data/lib/aws-sdk-resources/services/s3/object_copier.rb +99 -0
- data/lib/aws-sdk-resources/services/s3/object_multipart_copier.rb +180 -0
- data/lib/aws-sdk-resources/services/s3/object_summary.rb +73 -0
- data/lib/aws-sdk-resources/services/s3/presigned_post.rb +651 -0
- data/lib/aws-sdk-resources/services/sns.rb +7 -0
- data/lib/aws-sdk-resources/services/sns/message_verifier.rb +171 -0
- data/lib/aws-sdk-resources/services/sqs.rb +7 -0
- data/lib/aws-sdk-resources/services/sqs/queue_poller.rb +521 -0
- data/lib/aws-sdk-resources/source.rb +39 -0
- metadata +118 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
module Encryption
|
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
|
+
POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS + V2_ENVELOPE_KEYS).uniq
|
24
|
+
|
25
|
+
POSSIBLE_ENCRYPTION_FORMATS = %w(
|
26
|
+
AES/GCM/NoPadding
|
27
|
+
AES/CBC/PKCS5Padding
|
28
|
+
)
|
29
|
+
|
30
|
+
def call(context)
|
31
|
+
attach_http_event_listeners(context)
|
32
|
+
@handler.call(context)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def attach_http_event_listeners(context)
|
38
|
+
|
39
|
+
context.http_response.on_headers(200) do
|
40
|
+
cipher = decryption_cipher(context)
|
41
|
+
decrypter = body_contains_auth_tag?(context) ?
|
42
|
+
authenticated_decrypter(context, cipher) :
|
43
|
+
IODecrypter.new(cipher, context.http_response.body)
|
44
|
+
context.http_response.body = decrypter
|
45
|
+
end
|
46
|
+
|
47
|
+
context.http_response.on_success(200) do
|
48
|
+
decrypter = context.http_response.body
|
49
|
+
decrypter.finalize
|
50
|
+
decrypter.io.rewind if decrypter.io.respond_to?(:rewind)
|
51
|
+
context.http_response.body = decrypter.io
|
52
|
+
end
|
53
|
+
|
54
|
+
context.http_response.on_error do
|
55
|
+
if context.http_response.body.respond_to?(:io)
|
56
|
+
context.http_response.body = context.http_response.body.io
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def decryption_cipher(context)
|
62
|
+
if envelope = get_encryption_envelope(context)
|
63
|
+
context[:encryption][:cipher_provider].decryption_cipher(envelope)
|
64
|
+
else
|
65
|
+
raise Errors::DecryptionError, "unable to locate encryption envelope"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_encryption_envelope(context)
|
70
|
+
if context[:encryption][:envelope_location] == :metadata
|
71
|
+
envelope_from_metadata(context) || envelope_from_instr_file(context)
|
72
|
+
else
|
73
|
+
envelope_from_instr_file(context) || envelope_from_metadata(context)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def envelope_from_metadata(context)
|
78
|
+
possible_envelope = {}
|
79
|
+
POSSIBLE_ENVELOPE_KEYS.each do |suffix|
|
80
|
+
if value = context.http_response.headers["x-amz-meta-#{suffix}"]
|
81
|
+
possible_envelope[suffix] = value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
extract_envelope(possible_envelope)
|
85
|
+
end
|
86
|
+
|
87
|
+
def envelope_from_instr_file(context)
|
88
|
+
suffix = context[:encryption][:instruction_file_suffix]
|
89
|
+
possible_envelope = Json.load(context.client.get_object(
|
90
|
+
bucket: context.params[:bucket],
|
91
|
+
key: context.params[:key] + suffix
|
92
|
+
).body.read)
|
93
|
+
extract_envelope(possible_envelope)
|
94
|
+
rescue S3::Errors::ServiceError, Json::ParseError
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def extract_envelope(hash)
|
99
|
+
return v1_envelope(hash) if hash.key?('x-amz-key')
|
100
|
+
return v2_envelope(hash) if hash.key?('x-amz-key-v2')
|
101
|
+
if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
|
102
|
+
msg = "unsupported envelope encryption version #{$1}"
|
103
|
+
raise Errors::DecryptionError, msg
|
104
|
+
else
|
105
|
+
nil # no envelope found
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def v1_envelope(envelope)
|
110
|
+
envelope
|
111
|
+
end
|
112
|
+
|
113
|
+
def v2_envelope(envelope)
|
114
|
+
unless POSSIBLE_ENCRYPTION_FORMATS.include? envelope['x-amz-cek-alg']
|
115
|
+
alg = envelope['x-amz-cek-alg'].inspect
|
116
|
+
msg = "unsupported content encrypting key (cek) format: #{alg}"
|
117
|
+
raise Errors::DecryptionError, msg
|
118
|
+
end
|
119
|
+
unless envelope['x-amz-wrap-alg'] == 'kms'
|
120
|
+
# possible to support
|
121
|
+
# RSA/ECB/OAEPWithSHA-256AndMGF1Padding
|
122
|
+
alg = envelope['x-amz-wrap-alg'].inspect
|
123
|
+
msg = "unsupported key wrapping algorithm: #{alg}"
|
124
|
+
raise Errors::DecryptionError, msg
|
125
|
+
end
|
126
|
+
unless V2_ENVELOPE_KEYS.sort == envelope.keys.sort
|
127
|
+
msg = "incomplete v2 encryption envelope:\n"
|
128
|
+
msg += " expected: #{V2_ENVELOPE_KEYS.join(',')}\n"
|
129
|
+
msg += " got: #{envelope_keys.join(', ')}"
|
130
|
+
raise Errors::DecryptionError, msg
|
131
|
+
end
|
132
|
+
envelope
|
133
|
+
end
|
134
|
+
|
135
|
+
# When the x-amz-meta-x-amz-tag-len header is present, it indicates
|
136
|
+
# that the body of this object has a trailing auth tag. The header
|
137
|
+
# indicates the length of that tag.
|
138
|
+
#
|
139
|
+
# This method fetches the tag from the end of the object by
|
140
|
+
# making a GET Object w/range request. This auth tag is used
|
141
|
+
# to initialize the cipher, and the decrypter truncates the
|
142
|
+
# auth tag from the body when writing the final bytes.
|
143
|
+
def authenticated_decrypter(context, cipher)
|
144
|
+
http_resp = context.http_response
|
145
|
+
content_length = http_resp.headers['content-length'].to_i
|
146
|
+
auth_tag_length = http_resp.headers['x-amz-meta-x-amz-tag-len']
|
147
|
+
auth_tag_length = auth_tag_length.to_i / 8
|
148
|
+
|
149
|
+
auth_tag = context.client.get_object(
|
150
|
+
bucket: context.params[:bucket],
|
151
|
+
key: context.params[:key],
|
152
|
+
range: "bytes=-#{auth_tag_length}"
|
153
|
+
).body.read
|
154
|
+
|
155
|
+
cipher.auth_tag = auth_tag
|
156
|
+
cipher.auth_data = ''
|
157
|
+
|
158
|
+
# The encrypted object contains both the cipher text
|
159
|
+
# plus a trailing auth tag. This decrypter will the body
|
160
|
+
# expect for the trailing auth tag.
|
161
|
+
decrypter = IOAuthDecrypter.new(
|
162
|
+
io: http_resp.body,
|
163
|
+
encrypted_content_length: content_length - auth_tag_length,
|
164
|
+
cipher: cipher)
|
165
|
+
end
|
166
|
+
|
167
|
+
def body_contains_auth_tag?(context)
|
168
|
+
context.http_response.headers['x-amz-meta-x-amz-tag-len']
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
module Encryption
|
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
|
16
|
+
cipher = Utils.aes_encryption_cipher(:CBC)
|
17
|
+
envelope = {
|
18
|
+
'x-amz-key' => encode64(encrypt(envelope_key(cipher))),
|
19
|
+
'x-amz-iv' => encode64(envelope_iv(cipher)),
|
20
|
+
'x-amz-matdesc' => materials_description,
|
21
|
+
}
|
22
|
+
[envelope, cipher]
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Cipher] Given an encryption envelope, returns a
|
26
|
+
# decryption cipher.
|
27
|
+
def decryption_cipher(envelope)
|
28
|
+
master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
|
29
|
+
key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
|
30
|
+
iv = decode64(envelope['x-amz-iv'])
|
31
|
+
Utils.aes_decryption_cipher(:CBC, key, iv)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def envelope_key(cipher)
|
37
|
+
cipher.key = cipher.random_key
|
38
|
+
end
|
39
|
+
|
40
|
+
def envelope_iv(cipher)
|
41
|
+
cipher.iv = cipher.random_iv
|
42
|
+
end
|
43
|
+
|
44
|
+
def encrypt(data)
|
45
|
+
Utils.encrypt(@key_provider.encryption_materials.key, data)
|
46
|
+
end
|
47
|
+
|
48
|
+
def materials_description
|
49
|
+
@key_provider.encryption_materials.description
|
50
|
+
end
|
51
|
+
|
52
|
+
def encode64(str)
|
53
|
+
Base64.encode64(str).split("\n") * ""
|
54
|
+
end
|
55
|
+
|
56
|
+
def decode64(str)
|
57
|
+
Base64.decode64(str)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Aws
|
2
|
+
module S3
|
3
|
+
module Encryption
|
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,50 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
module Encryption
|
6
|
+
# @api private
|
7
|
+
class EncryptHandler < Seahorse::Client::Handler
|
8
|
+
|
9
|
+
def call(context)
|
10
|
+
envelope, cipher = context[:encryption][:cipher_provider].encryption_cipher
|
11
|
+
apply_encryption_envelope(context, envelope, cipher)
|
12
|
+
apply_encryption_cipher(context, cipher)
|
13
|
+
@handler.call(context)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def apply_encryption_envelope(context, envelope, cipher)
|
19
|
+
context[:encryption][:cipher] = cipher
|
20
|
+
if context[:encryption][:envelope_location] == :metadata
|
21
|
+
context.params[:metadata] ||= {}
|
22
|
+
context.params[:metadata].update(envelope)
|
23
|
+
else # :instruction_file
|
24
|
+
suffix = context[:encryption][:instruction_file_suffix]
|
25
|
+
context.client.put_object(
|
26
|
+
bucket: context.params[:bucket],
|
27
|
+
key: context.params[:key] + suffix,
|
28
|
+
body: Json.dump(envelope)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply_encryption_cipher(context, cipher)
|
34
|
+
io = context.params[:body] || ''
|
35
|
+
io = StringIO.new(io) if String === io
|
36
|
+
context.params[:body] = IOEncrypter.new(cipher, io)
|
37
|
+
context.params[:metadata] ||= {}
|
38
|
+
context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
|
39
|
+
if md5 = context.params.delete(:content_md5)
|
40
|
+
context.params[:metadata]['x-amz-unencrypted-content-md5'] = md5
|
41
|
+
end
|
42
|
+
context.http_response.on_headers do
|
43
|
+
context.params[:body].close
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Aws
|
2
|
+
module S3
|
3
|
+
module Encryption
|
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
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Aws
|
2
|
+
module S3
|
3
|
+
module Encryption
|
4
|
+
# @api private
|
5
|
+
class IODecrypter
|
6
|
+
|
7
|
+
# @param [OpenSSL::Cipher] cipher
|
8
|
+
# @param [IO#write] io An IO-like object that responds to `#write`.
|
9
|
+
def initialize(cipher, io)
|
10
|
+
@cipher = cipher.clone
|
11
|
+
@io = io
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [#write]
|
15
|
+
attr_reader :io
|
16
|
+
|
17
|
+
def write(chunk)
|
18
|
+
# decrypt and write
|
19
|
+
@io.write(@cipher.update(chunk))
|
20
|
+
end
|
21
|
+
|
22
|
+
def finalize
|
23
|
+
@io.write(@cipher.final)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module S3
|
6
|
+
module Encryption
|
7
|
+
|
8
|
+
# Provides an IO wrapper encrpyting a stream of data.
|
9
|
+
# It is possible to use this same object for decrypting. You must
|
10
|
+
# initialize it with a decryptiion cipher in that case and the
|
11
|
+
# IO object must contain cipher text instead of plain text.
|
12
|
+
# @api private
|
13
|
+
class IOEncrypter
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
ONE_MEGABYTE = 1024 * 1024
|
17
|
+
|
18
|
+
def initialize(cipher, io)
|
19
|
+
@encrypted = io.size <= ONE_MEGABYTE ?
|
20
|
+
encrypt_to_stringio(cipher, io.read) :
|
21
|
+
encrypt_to_tempfile(cipher, io)
|
22
|
+
@size = @encrypted.size
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Integer]
|
26
|
+
attr_reader :size
|
27
|
+
|
28
|
+
def read(bytes = nil, output_buffer = nil)
|
29
|
+
if Tempfile === @encrypted && @encrypted.closed?
|
30
|
+
@encrypted.open
|
31
|
+
@encrypted.binmode
|
32
|
+
end
|
33
|
+
@encrypted.read(bytes, output_buffer)
|
34
|
+
end
|
35
|
+
|
36
|
+
def rewind
|
37
|
+
@encrypted.rewind
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def close
|
42
|
+
@encrypted.close if Tempfile === @encrypted
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def encrypt_to_stringio(cipher, plain_text)
|
48
|
+
if plain_text.empty?
|
49
|
+
StringIO.new(cipher.final)
|
50
|
+
else
|
51
|
+
StringIO.new(cipher.update(plain_text) + cipher.final)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def encrypt_to_tempfile(cipher, io)
|
56
|
+
encrypted = Tempfile.new(self.object_id.to_s)
|
57
|
+
encrypted.binmode
|
58
|
+
while chunk = io.read(ONE_MEGABYTE)
|
59
|
+
encrypted.write(cipher.update(chunk))
|
60
|
+
end
|
61
|
+
encrypted.write(cipher.final)
|
62
|
+
encrypted.rewind
|
63
|
+
encrypted
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|