porky_lib 0.9.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -3
- data/.rubocop.yml +58 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +50 -43
- data/README.md +117 -9
- data/Rakefile +1 -0
- data/lib/porky_lib/aws/kms/client.rb +1 -1
- data/lib/porky_lib/file_service.rb +35 -9
- data/lib/porky_lib/file_service_helper.rb +39 -13
- data/lib/porky_lib/unencrypted/file_service.rb +28 -5
- data/lib/porky_lib/version.rb +1 -1
- data/lib/tasks/file.rake +85 -0
- data/porky_lib.gemspec +1 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70a7962acaef46a1b1e4cd9e1decaccbe5bb35867de03bbc8c4d24329f0ef4be
|
4
|
+
data.tar.gz: 81cbd165551dcafd6fb595e24a74af691143858bb3d8c9f70c4d8d1cb3d0a580
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5fbc041473d83b4f4ad03321d3f30ba40990c139f215dc98a388c99999cb747415287a2c822bedb6f3dc2f71d37f1ceb72017ada14b65aba88584555ff448fb
|
7
|
+
data.tar.gz: 292725e636df669d3022edb4cd7f566b1b472b60dca17c1e8db1351c107ad06799e4b4b805425a5b58282b9c50bab57519033cf37e39286a3d71098474a5d0f3
|
data/.circleci/config.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -9,7 +9,8 @@ AllCops:
|
|
9
9
|
- node_modules/**/*
|
10
10
|
- output/**/*
|
11
11
|
- vendor/**/*
|
12
|
-
|
12
|
+
- spec/porky_lib/data/*
|
13
|
+
TargetRubyVersion: 2.7.1
|
13
14
|
RSpec:
|
14
15
|
Patterns:
|
15
16
|
- _spec.rb
|
@@ -17,10 +18,22 @@ AllCops:
|
|
17
18
|
SpecTypes:
|
18
19
|
Feature: 'spec/features/**/*'
|
19
20
|
|
20
|
-
Documentation:
|
21
|
+
Style/Documentation:
|
21
22
|
Enabled: false
|
22
23
|
|
23
|
-
|
24
|
+
Security/MarshalLoad:
|
25
|
+
Enabled: true
|
26
|
+
|
27
|
+
Security/Eval:
|
28
|
+
Enabled: true
|
29
|
+
|
30
|
+
Security/YAMLLoad:
|
31
|
+
Enabled: true
|
32
|
+
|
33
|
+
Security/JSONLoad:
|
34
|
+
Enabled: true
|
35
|
+
|
36
|
+
Layout/LineLength:
|
24
37
|
Max: 160
|
25
38
|
|
26
39
|
Metrics/ClassLength:
|
@@ -46,3 +59,45 @@ RSpec/MultipleExpectations:
|
|
46
59
|
|
47
60
|
RSpec/ExampleLength:
|
48
61
|
Max: 10
|
62
|
+
|
63
|
+
Style/HashEachMethods:
|
64
|
+
Enabled: true
|
65
|
+
|
66
|
+
Style/HashTransformKeys:
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
Style/HashTransformValues:
|
70
|
+
Enabled: true
|
71
|
+
|
72
|
+
Lint/RaiseException:
|
73
|
+
Enabled: true
|
74
|
+
|
75
|
+
Lint/StructNewOverride:
|
76
|
+
Enabled: true
|
77
|
+
|
78
|
+
Layout/SpaceAroundMethodCallOperator:
|
79
|
+
Enabled: true
|
80
|
+
|
81
|
+
Style/ExponentialNotation:
|
82
|
+
Enabled: true
|
83
|
+
|
84
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
85
|
+
Enabled: true
|
86
|
+
|
87
|
+
Lint/DeprecatedOpenSSLConstant:
|
88
|
+
Enabled: true
|
89
|
+
|
90
|
+
Style/SlicingWithRange:
|
91
|
+
Enabled: true
|
92
|
+
|
93
|
+
Lint/MixedRegexpCaptureTypes:
|
94
|
+
Enabled: true
|
95
|
+
|
96
|
+
Style/RedundantRegexpCharacterClass:
|
97
|
+
Enabled: true
|
98
|
+
|
99
|
+
Style/RedundantRegexpEscape:
|
100
|
+
Enabled: true
|
101
|
+
|
102
|
+
Style/RedundantFetchBlock:
|
103
|
+
Enabled: true
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
porky_lib (0.
|
4
|
+
porky_lib (0.11.0)
|
5
5
|
aws-sdk-kms
|
6
6
|
aws-sdk-s3
|
7
7
|
msgpack
|
@@ -11,85 +11,91 @@ PATH
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
ast (2.4.
|
15
|
-
aws-eventstream (1.0
|
16
|
-
aws-partitions (1.
|
17
|
-
aws-sdk-core (3.
|
18
|
-
aws-eventstream (~> 1
|
19
|
-
aws-partitions (~> 1, >= 1.
|
14
|
+
ast (2.4.1)
|
15
|
+
aws-eventstream (1.1.0)
|
16
|
+
aws-partitions (1.338.0)
|
17
|
+
aws-sdk-core (3.103.0)
|
18
|
+
aws-eventstream (~> 1, >= 1.0.2)
|
19
|
+
aws-partitions (~> 1, >= 1.239.0)
|
20
20
|
aws-sigv4 (~> 1.1)
|
21
21
|
jmespath (~> 1.0)
|
22
|
-
aws-sdk-kms (1.
|
23
|
-
aws-sdk-core (~> 3, >= 3.
|
22
|
+
aws-sdk-kms (1.36.0)
|
23
|
+
aws-sdk-core (~> 3, >= 3.99.0)
|
24
24
|
aws-sigv4 (~> 1.1)
|
25
|
-
aws-sdk-s3 (1.
|
26
|
-
aws-sdk-core (~> 3, >= 3.
|
25
|
+
aws-sdk-s3 (1.73.0)
|
26
|
+
aws-sdk-core (~> 3, >= 3.102.1)
|
27
27
|
aws-sdk-kms (~> 1)
|
28
28
|
aws-sigv4 (~> 1.1)
|
29
|
-
aws-sigv4 (1.1
|
30
|
-
aws-eventstream (~> 1
|
31
|
-
bundler-audit (0.
|
29
|
+
aws-sigv4 (1.2.1)
|
30
|
+
aws-eventstream (~> 1, >= 1.0.2)
|
31
|
+
bundler-audit (0.7.0.1)
|
32
32
|
bundler (>= 1.2.0, < 3)
|
33
|
-
thor (
|
34
|
-
byebug (11.
|
35
|
-
|
33
|
+
thor (>= 0.18, < 2)
|
34
|
+
byebug (11.1.3)
|
35
|
+
codacy-coverage (2.2.1)
|
36
|
+
simplecov
|
37
|
+
codecov (0.1.17)
|
36
38
|
json
|
37
39
|
simplecov
|
38
40
|
url
|
39
41
|
diff-lcs (1.3)
|
40
42
|
docile (1.3.2)
|
41
|
-
ffi (1.
|
42
|
-
jaro_winkler (1.5.3)
|
43
|
+
ffi (1.12.2)
|
43
44
|
jmespath (1.4.0)
|
44
|
-
json (2.
|
45
|
-
msgpack (1.3.
|
46
|
-
parallel (1.
|
47
|
-
parser (2.
|
48
|
-
ast (~> 2.4.
|
45
|
+
json (2.3.0)
|
46
|
+
msgpack (1.3.3)
|
47
|
+
parallel (1.19.2)
|
48
|
+
parser (2.7.1.4)
|
49
|
+
ast (~> 2.4.1)
|
49
50
|
rainbow (3.0.0)
|
50
|
-
rake (13.0.
|
51
|
+
rake (13.0.1)
|
51
52
|
rbnacl (5.0.0)
|
52
53
|
ffi
|
53
54
|
rbnacl-libsodium (1.0.16)
|
54
55
|
rbnacl (>= 3.0.1)
|
56
|
+
regexp_parser (1.7.1)
|
57
|
+
rexml (3.2.4)
|
55
58
|
rspec (3.9.0)
|
56
59
|
rspec-core (~> 3.9.0)
|
57
60
|
rspec-expectations (~> 3.9.0)
|
58
61
|
rspec-mocks (~> 3.9.0)
|
59
62
|
rspec-collection_matchers (1.2.0)
|
60
63
|
rspec-expectations (>= 2.99.0.beta1)
|
61
|
-
rspec-core (3.9.
|
62
|
-
rspec-support (~> 3.9.
|
64
|
+
rspec-core (3.9.2)
|
65
|
+
rspec-support (~> 3.9.3)
|
63
66
|
rspec-expectations (3.9.0)
|
64
67
|
diff-lcs (>= 1.2.0, < 2.0)
|
65
68
|
rspec-support (~> 3.9.0)
|
66
|
-
rspec-mocks (3.9.
|
69
|
+
rspec-mocks (3.9.1)
|
67
70
|
diff-lcs (>= 1.2.0, < 2.0)
|
68
71
|
rspec-support (~> 3.9.0)
|
69
|
-
rspec-support (3.9.
|
72
|
+
rspec-support (3.9.3)
|
70
73
|
rspec_junit_formatter (0.4.1)
|
71
74
|
rspec-core (>= 2, < 4, != 2.12.0)
|
72
|
-
rubocop (0.
|
73
|
-
jaro_winkler (~> 1.5.1)
|
75
|
+
rubocop (0.86.0)
|
74
76
|
parallel (~> 1.10)
|
75
|
-
parser (>= 2.
|
77
|
+
parser (>= 2.7.0.1)
|
76
78
|
rainbow (>= 2.2.2, < 4.0)
|
79
|
+
regexp_parser (>= 1.7)
|
80
|
+
rexml
|
81
|
+
rubocop-ast (>= 0.0.3, < 1.0)
|
77
82
|
ruby-progressbar (~> 1.7)
|
78
|
-
unicode-display_width (>= 1.4.0, <
|
79
|
-
rubocop-
|
83
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
84
|
+
rubocop-ast (0.0.3)
|
85
|
+
parser (>= 2.7.0.1)
|
86
|
+
rubocop-performance (1.6.1)
|
80
87
|
rubocop (>= 0.71.0)
|
81
|
-
rubocop-rspec (1.
|
88
|
+
rubocop-rspec (1.40.0)
|
82
89
|
rubocop (>= 0.68.1)
|
83
90
|
rubocop_runner (2.2.0)
|
84
91
|
ruby-progressbar (1.10.1)
|
85
|
-
simplecov (0.
|
92
|
+
simplecov (0.18.5)
|
86
93
|
docile (~> 1.1)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
thor (0.20.3)
|
94
|
+
simplecov-html (~> 0.11)
|
95
|
+
simplecov-html (0.12.2)
|
96
|
+
thor (1.0.1)
|
91
97
|
timecop (0.9.1)
|
92
|
-
unicode-display_width (1.
|
98
|
+
unicode-display_width (1.7.0)
|
93
99
|
url (0.3.2)
|
94
100
|
|
95
101
|
PLATFORMS
|
@@ -101,6 +107,7 @@ DEPENDENCIES
|
|
101
107
|
bundler
|
102
108
|
bundler-audit
|
103
109
|
byebug
|
110
|
+
codacy-coverage
|
104
111
|
codecov
|
105
112
|
msgpack
|
106
113
|
porky_lib!
|
@@ -119,7 +126,7 @@ DEPENDENCIES
|
|
119
126
|
timecop
|
120
127
|
|
121
128
|
RUBY VERSION
|
122
|
-
ruby 2.
|
129
|
+
ruby 2.7.1p83
|
123
130
|
|
124
131
|
BUNDLED WITH
|
125
|
-
2.
|
132
|
+
2.1.4
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ And then execute:
|
|
20
20
|
Or install it yourself as:
|
21
21
|
|
22
22
|
$ gem install porky_lib
|
23
|
-
|
23
|
+
|
24
24
|
Inside of your Ruby program do:
|
25
25
|
|
26
26
|
```ruby
|
@@ -86,7 +86,7 @@ To encrypt data with a known plaintext key:
|
|
86
86
|
# plaintext_key is the encryption key to use
|
87
87
|
# encryption_info is the structure returned that contains:
|
88
88
|
# ciphertext: plaintext encrypted under plaintext_key
|
89
|
-
# nonce: The generated nonce
|
89
|
+
# nonce: The generated nonce
|
90
90
|
encryption_info = PorkyLib::Symmetric.instance.encrypt_with_key(plaintext, plaintext_key)
|
91
91
|
```
|
92
92
|
|
@@ -104,7 +104,7 @@ To decrypt data with a known plaintext key:
|
|
104
104
|
```ruby
|
105
105
|
# Where ciphertext is the encrypted data to be decrypted
|
106
106
|
# plaintext_key is the decryption key to use
|
107
|
-
# nonce is the nonce to use
|
107
|
+
# nonce is the nonce to use
|
108
108
|
# decryption_info is the structured returned that contains:
|
109
109
|
# plaintext: ciphertext decrypted under plaintext_key
|
110
110
|
decryption_info = PorkyLib::Symmetric.instance.decrypt_with_key(ciphertext, plaintext_key, nonce)
|
@@ -137,7 +137,7 @@ plaintext_key.replace(PorkyLib::Symmetric.instance.secure_delete_plaintext_key(p
|
|
137
137
|
To verify whether an alias exists or not:
|
138
138
|
```ruby
|
139
139
|
# Where key_alias is the alias name to verify
|
140
|
-
alias_exists = PorkyLib::Symmetric.instance.cmk_alias_exists?(key_alias)
|
140
|
+
alias_exists = PorkyLib::Symmetric.instance.cmk_alias_exists?(key_alias)
|
141
141
|
```
|
142
142
|
|
143
143
|
### To Read From AWS S3
|
@@ -156,21 +156,57 @@ file_data = PorkyLib::Unencrypted::FileService.read(bucket_name, file_key)
|
|
156
156
|
|
157
157
|
### To Write To AWS S3
|
158
158
|
```ruby
|
159
|
-
#
|
159
|
+
# --- DEPRECATED --- Please use write_data or write_file instead of write
|
160
|
+
# Where file is the data to encrypt and upload to S3 (can be a path or raw data or ruby file object)
|
160
161
|
# bucket_name is the name of the S3 bucket to write to
|
161
162
|
# key_id is the ID of the CMK to use to generate a data encryption key to encrypt the file data
|
162
|
-
# options is an optional parameter for specifying optional metadata about the file
|
163
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
163
164
|
file_key = PorkyLib::FileService.write(file, bucket_name, key_id, options)
|
164
165
|
```
|
165
166
|
|
166
|
-
### To Write
|
167
|
+
### To Write Files To AWS S3
|
167
168
|
```ruby
|
168
|
-
# Where file is the data to upload to S3 (can be
|
169
|
+
# Where file is the data to encrypt and upload to S3 (can be a path or ruby file object)
|
169
170
|
# bucket_name is the name of the S3 bucket to write to
|
170
|
-
#
|
171
|
+
# key_id is the ID of the CMK to use to generate a data encryption key to encrypt the file data
|
172
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
173
|
+
file_key = PorkyLib::FileService.write_file(file, bucket_name, key_id, options)
|
174
|
+
```
|
175
|
+
|
176
|
+
### To Write Data To AWS S3
|
177
|
+
```ruby
|
178
|
+
# Where data is the raw data to encrypt and upload to S3
|
179
|
+
# bucket_name is the name of the S3 bucket to write to
|
180
|
+
# key_id is the ID of the CMK to use to generate a data encryption key to encrypt the file data
|
181
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
182
|
+
file_key = PorkyLib::FileService.write_data(data, bucket_name, key_id, options)
|
183
|
+
```
|
184
|
+
|
185
|
+
### To Write Unencrypted To AWS S3
|
186
|
+
```ruby
|
187
|
+
# --- DEPRECATED --- Please use write_data or write_file instead of write
|
188
|
+
# Where file is the data to upload to S3 (can be a path or raw data or ruby file object)
|
189
|
+
# bucket_name is the name of the S3 bucket to write to
|
190
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
171
191
|
file_key = PorkyLib::Unencrypted::FileService.write(file, bucket_name, options)
|
172
192
|
```
|
173
193
|
|
194
|
+
### To Write Unencrypted Files To AWS S3
|
195
|
+
```ruby
|
196
|
+
# Where file is the data to encrypt and upload to S3 (can be a path or ruby file object)
|
197
|
+
# bucket_name is the name of the S3 bucket to write to
|
198
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
199
|
+
file_key = PorkyLib::Unencrypted::FileService.write_file(file, bucket_name, options)
|
200
|
+
```
|
201
|
+
|
202
|
+
### To Write Unencrypted Data To AWS S3
|
203
|
+
```ruby
|
204
|
+
# Where data is the raw data to encrypt and upload to S3
|
205
|
+
# bucket_name is the name of the S3 bucket to write to
|
206
|
+
# options is an optional parameter for specifying optional metadata about the file and the storage_class of the object
|
207
|
+
file_key = PorkyLib::Unencrypted::FileService.write_data(data, bucket_name, options)
|
208
|
+
```
|
209
|
+
|
174
210
|
### Generate S3 Presigned POST URL
|
175
211
|
To generate a new presigned POST url (used to upload files directly to AWS S3):
|
176
212
|
```ruby
|
@@ -188,12 +224,84 @@ To generate a new presigned GET url (used to download files directly from AWS S3
|
|
188
224
|
url = PorkyLib::Symmetric.instance.presigned_get_url(bucket_name, file_key)
|
189
225
|
```
|
190
226
|
|
227
|
+
## Rake task
|
228
|
+
If you want to write or read an encrypted file from the command line, there is a Rake write and read task.
|
229
|
+
|
230
|
+
> Note: the environment variables can be set globally or by prepending them to the rake task command
|
231
|
+
|
232
|
+
### Write file
|
233
|
+
|
234
|
+
Rake task name: `file:write`
|
235
|
+
|
236
|
+
Environment variables:
|
237
|
+
* Required
|
238
|
+
* `FILE_PATH` - Absolute or relative file path
|
239
|
+
* `CMK_KEY_ID` - Alias of the CMK key
|
240
|
+
* `AWS_S3_BUCKET` - AWS S3 bucket name
|
241
|
+
* `AWS_REGION` - AWS region name
|
242
|
+
* `AWS_ACCESS_KEY_ID` - AWS access key ID (credentials)
|
243
|
+
* `AWS_ACCESS_KEY` - AWS secret access key (credentials)
|
244
|
+
* Optional
|
245
|
+
* `AWS_S3_MOCK_CLIENT` - PorkyLib's AWS KMS mock client (defaults to `true`)
|
246
|
+
* `AWS_S3_MAX_FILE_SIZE` - Max file size (defaults to `1MB`)
|
247
|
+
* `AWS_S3_STORAGE_CLASS` - One of STANDARD, REDUCED_REDUNDANCY, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, GLACIER, DEEP_ARCHIVE (defaults to `STANDARD`)
|
248
|
+
* `AWS_S3_KEEP_FILE_NAME` - Saves the file in AWS S3 with the original file name (defaults to `true`)
|
249
|
+
|
250
|
+
### Read file
|
251
|
+
|
252
|
+
Rake task name: `file:read`
|
253
|
+
|
254
|
+
Environment variables:
|
255
|
+
* Required
|
256
|
+
* `FILE_KEY` - AWS S3 object file key
|
257
|
+
* `AWS_S3_BUCKET` - AWS S3 bucket name
|
258
|
+
* `AWS_REGION` - AWS region name
|
259
|
+
* `AWS_ACCESS_KEY_ID` - AWS access key ID (credentials)
|
260
|
+
* `AWS_ACCESS_KEY` - AWS secret access key (credentials)
|
261
|
+
* Optional
|
262
|
+
* `AWS_S3_MOCK_CLIENT` - PorkyLib's AWS KMS mock client (defaults to `true`)
|
263
|
+
* `AWS_S3_MAX_FILE_SIZE` - Max file size (defaults to `1MB`)
|
264
|
+
* `DESTINATION` - Location to save the file (defaults to `FILE_KEY`)
|
265
|
+
|
191
266
|
## Development
|
192
267
|
|
193
268
|
Development on this project should occur on separate feature branches and pull requests should be submitted. When submitting a
|
194
269
|
pull request, the pull request comment template should be filled out as much as possible to ensure a quick review and increase
|
195
270
|
the likelihood of the pull request being accepted.
|
196
271
|
|
272
|
+
### Ruby
|
273
|
+
|
274
|
+
This application requires:
|
275
|
+
|
276
|
+
* Ruby version: 2.7.1
|
277
|
+
|
278
|
+
Ruby 2.7.1 and greater requires OpenSSL 1.1+. To link to Homebrew's upgraded version of OpenSSL, add the following to your bash profile
|
279
|
+
|
280
|
+
```shell script
|
281
|
+
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1)"
|
282
|
+
```
|
283
|
+
|
284
|
+
If you do not have Ruby installed, it is recommended you use ruby-install and chruby to manage Ruby versions.
|
285
|
+
|
286
|
+
```bash
|
287
|
+
brew install ruby-install chruby
|
288
|
+
ruby-install ruby 2.7.1
|
289
|
+
```
|
290
|
+
|
291
|
+
Add the following lines to ~/.bash_profile:
|
292
|
+
|
293
|
+
```bash
|
294
|
+
source /usr/local/opt/chruby/share/chruby/chruby.sh
|
295
|
+
source /usr/local/opt/chruby/share/chruby/auto.sh
|
296
|
+
```
|
297
|
+
|
298
|
+
Set Ruby version to 2.7.1:
|
299
|
+
|
300
|
+
```bash
|
301
|
+
source ~/.bash_profile
|
302
|
+
chruby 2.7.1
|
303
|
+
```
|
304
|
+
|
197
305
|
### Running Tests
|
198
306
|
|
199
307
|
```ruby
|
data/Rakefile
CHANGED
@@ -72,7 +72,7 @@ class Aws::KMS::Client
|
|
72
72
|
|
73
73
|
def decrypt(ciphertext_blob:, encryption_context: nil)
|
74
74
|
key_id, decoded_context, plaintext = MessagePack.unpack(ciphertext_blob.reverse)
|
75
|
-
decoded_context =
|
75
|
+
decoded_context = decoded_context.transform_keys(&:to_sym) if decoded_context
|
76
76
|
raise Aws::KMS::Errors::InvalidCiphertextException.new(nil, nil) unless decoded_context == encryption_context
|
77
77
|
|
78
78
|
Aws::KMS::Types::DecryptResponse.new(
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'singleton'
|
4
4
|
|
5
5
|
class PorkyLib::FileService
|
6
|
+
extend Gem::Deprecate
|
7
|
+
|
6
8
|
include Singleton
|
7
9
|
include PorkyLib::FileServiceHelper
|
8
10
|
|
@@ -56,10 +58,30 @@ class PorkyLib::FileService
|
|
56
58
|
|
57
59
|
def write(file, bucket_name, key_id, options = {})
|
58
60
|
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(file, bucket_name, key_id)
|
59
|
-
raise FileSizeTooLargeError, "File size is larger than maximum allowed size of #{max_file_size}" if file_size_invalid?(file)
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
if file?(file)
|
63
|
+
write_file(file, bucket_name, key_id, options)
|
64
|
+
else
|
65
|
+
write_data(file, bucket_name, key_id, options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
deprecate :write, 'write_file or write_data', 2020, 1
|
69
|
+
|
70
|
+
def write_file(file, bucket_name, key_id, options = {})
|
71
|
+
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(file, bucket_name, key_id)
|
72
|
+
|
73
|
+
write_data(read_file(file), bucket_name, key_id, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def write_data(data, bucket_name, key_id, options = {})
|
77
|
+
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(data, bucket_name, key_id)
|
78
|
+
raise FileSizeTooLargeError, "Data size is larger than maximum allowed size of #{max_file_size}" if data_size_invalid?(data)
|
79
|
+
|
80
|
+
file_key = if options.key?(:file_name)
|
81
|
+
options[:file_name]
|
82
|
+
else
|
83
|
+
generate_file_key(options)
|
84
|
+
end
|
63
85
|
tempfile = encrypt_file_contents(data, key_id, file_key, options)
|
64
86
|
|
65
87
|
begin
|
@@ -73,12 +95,12 @@ class PorkyLib::FileService
|
|
73
95
|
file_key
|
74
96
|
end
|
75
97
|
|
76
|
-
def overwrite_file(
|
77
|
-
raise FileServiceError, 'Invalid input. One or more input values is nil' if
|
98
|
+
def overwrite_file(data, file_key, bucket_name, key_id, options = {})
|
99
|
+
raise FileServiceError, 'Invalid input. One or more input values is nil' if overwrite_input_invalid?(data, file_key, bucket_name, key_id)
|
78
100
|
raise FileServiceError, 'Invalid input. file_key cannot be nil if overwriting an existing file' if file_key.nil?
|
79
|
-
raise FileSizeTooLargeError, "File size is larger than maximum allowed size of #{max_file_size}" if file_size_invalid?(file)
|
80
101
|
|
81
|
-
|
102
|
+
raise FileSizeTooLargeError, "File size is larger than maximum allowed size of #{max_file_size}" if data_size_invalid?(data)
|
103
|
+
|
82
104
|
tempfile = encrypt_file_contents(data, key_id, file_key, options)
|
83
105
|
|
84
106
|
begin
|
@@ -158,7 +180,11 @@ class PorkyLib::FileService
|
|
158
180
|
@s3_client ||= Aws::S3::Client.new
|
159
181
|
end
|
160
182
|
|
161
|
-
def input_invalid?(
|
162
|
-
|
183
|
+
def input_invalid?(file_or_data, bucket_name, key_id)
|
184
|
+
file_or_data.nil? || bucket_name.nil? || key_id.nil?
|
185
|
+
end
|
186
|
+
|
187
|
+
def overwrite_input_invalid?(file_or_data, file_key, bucket_name, key_id)
|
188
|
+
file_or_data.nil? || file_key.nil? || bucket_name.nil? || key_id.nil?
|
163
189
|
end
|
164
190
|
end
|
@@ -3,17 +3,18 @@
|
|
3
3
|
require 'aws-sdk-s3'
|
4
4
|
|
5
5
|
module PorkyLib::FileServiceHelper
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
extend Gem::Deprecate
|
7
|
+
|
8
|
+
class FileServiceError < StandardError; end
|
9
|
+
|
10
|
+
def data_size_invalid?(data)
|
11
|
+
data.bytesize > max_size
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
a_file?(file_or_content) ?
|
14
|
+
def file?(file_or_content)
|
15
|
+
a_file?(file_or_content) || a_path?(file_or_content)
|
16
16
|
end
|
17
|
+
deprecate :file?, :none, 2020, 1
|
17
18
|
|
18
19
|
def write_tempfile(file_contents, file_key)
|
19
20
|
tempfile = Tempfile.new(file_key)
|
@@ -23,13 +24,25 @@ module PorkyLib::FileServiceHelper
|
|
23
24
|
tempfile
|
24
25
|
end
|
25
26
|
|
27
|
+
def read_file(file)
|
28
|
+
raise FileServiceError, 'file cannot be nil' if file.nil?
|
29
|
+
return file if !a_file?(file) && contain_null_byte?(file)
|
30
|
+
raise FileServiceError, 'The specified file does not exist' unless File.file?(file)
|
31
|
+
|
32
|
+
File.read(file)
|
33
|
+
rescue Errno::EACCES
|
34
|
+
raise FileServiceError, 'The specified file cannot be read, no permissions'
|
35
|
+
end
|
36
|
+
|
26
37
|
def perform_upload(bucket_name, file_key, tempfile, options)
|
27
38
|
obj = s3.bucket(bucket_name).object(file_key)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
39
|
+
|
40
|
+
upload_options = {
|
41
|
+
metadata: (options[:metadata] if options.key?(:metadata)),
|
42
|
+
storage_class: (options[:storage_class] if options.key?(:storage_class))
|
43
|
+
}.compact
|
44
|
+
|
45
|
+
obj.upload_file(tempfile.path, upload_options)
|
33
46
|
end
|
34
47
|
|
35
48
|
def s3
|
@@ -58,4 +71,17 @@ module PorkyLib::FileServiceHelper
|
|
58
71
|
def a_file?(file_or_content)
|
59
72
|
!file_or_content.is_a?(String)
|
60
73
|
end
|
74
|
+
|
75
|
+
def a_path?(content_or_path)
|
76
|
+
return false if contain_null_byte?(content_or_path)
|
77
|
+
|
78
|
+
File.file?(content_or_path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def contain_null_byte?(data)
|
82
|
+
null_byte = (+"\u0000").force_encoding("ASCII-8BIT")
|
83
|
+
data = (+data).force_encoding("ASCII-8BIT")
|
84
|
+
|
85
|
+
data.include?(null_byte)
|
86
|
+
end
|
61
87
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'singleton'
|
4
4
|
|
5
5
|
class PorkyLib::Unencrypted::FileService
|
6
|
+
extend Gem::Deprecate
|
7
|
+
|
6
8
|
include Singleton
|
7
9
|
include PorkyLib::FileServiceHelper
|
8
10
|
|
@@ -26,10 +28,31 @@ class PorkyLib::Unencrypted::FileService
|
|
26
28
|
|
27
29
|
def write(file, bucket_name, options = {})
|
28
30
|
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(file, bucket_name)
|
29
|
-
raise FileSizeTooLargeError, "File size is larger than maximum allowed size of #{max_file_size}" if file_size_invalid?(file)
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
if file?(file)
|
33
|
+
write_file(file, bucket_name, options)
|
34
|
+
else
|
35
|
+
write_data(file, bucket_name, options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
deprecate :write, 'write_file or write_data', 2020, 1
|
39
|
+
|
40
|
+
def write_file(file, bucket_name, options = {})
|
41
|
+
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(file, bucket_name)
|
42
|
+
|
43
|
+
write_data(read_file(file), bucket_name, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_data(data, bucket_name, options = {})
|
47
|
+
raise FileServiceError, 'Invalid input. One or more input values is nil' if input_invalid?(data, bucket_name)
|
48
|
+
raise FileSizeTooLargeError, "Data size is larger than maximum allowed size of #{max_file_size}" if data_size_invalid?(data)
|
49
|
+
|
50
|
+
file_key = if options.key?(:file_name)
|
51
|
+
options[:file_name]
|
52
|
+
else
|
53
|
+
generate_file_key(options)
|
54
|
+
end
|
55
|
+
tempfile = write_tempfile(data, file_key)
|
33
56
|
|
34
57
|
begin
|
35
58
|
perform_upload(bucket_name, file_key, tempfile, options)
|
@@ -42,7 +65,7 @@ class PorkyLib::Unencrypted::FileService
|
|
42
65
|
|
43
66
|
private
|
44
67
|
|
45
|
-
def input_invalid?(
|
46
|
-
|
68
|
+
def input_invalid?(file_or_data, bucket_name)
|
69
|
+
file_or_data.nil? || bucket_name.nil?
|
47
70
|
end
|
48
71
|
end
|
data/lib/porky_lib/version.rb
CHANGED
data/lib/tasks/file.rake
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'porky_lib'
|
4
|
+
|
5
|
+
namespace :file do
|
6
|
+
desc "Read a file from AWS S3"
|
7
|
+
task :read do
|
8
|
+
# Optional arguments
|
9
|
+
use_mock_client = ENV.fetch('AWS_S3_MOCK_CLIENT', 'true') == 'true'
|
10
|
+
max_file_size = ENV.fetch('AWS_S3_MAX_FILE_SIZE', 1_048_576).to_i
|
11
|
+
destination = ENV.fetch('DESTINATION', ENV['FILE_KEY'])
|
12
|
+
|
13
|
+
# Required arguments
|
14
|
+
arguments = {
|
15
|
+
file_key: ENV['FILE_KEY'],
|
16
|
+
aws_s3_bucket: ENV['AWS_S3_BUCKET'],
|
17
|
+
aws_region: ENV['AWS_REGION'],
|
18
|
+
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
19
|
+
aws_access_key: ENV['AWS_ACCESS_KEY']
|
20
|
+
}
|
21
|
+
|
22
|
+
# Checks presence of required arguments and configures porky_lib
|
23
|
+
check_arguments(arguments)
|
24
|
+
setup_porky_lib(arguments, use_mock_client, max_file_size)
|
25
|
+
|
26
|
+
# Reads and writes the file
|
27
|
+
message, = PorkyLib::FileService.instance.read(arguments[:aws_s3_bucket], arguments[:file_key])
|
28
|
+
file = File.open(destination, 'w')
|
29
|
+
file.puts(message)
|
30
|
+
file.close
|
31
|
+
|
32
|
+
puts "SUCCESS - Saved file: '#{destination}' with content of the bucket: '#{arguments[:aws_s3_bucket]}' with file_key: '#{arguments[:file_key]}'"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Write a file to AWS S3"
|
36
|
+
task :write do
|
37
|
+
# Optional arguments
|
38
|
+
use_mock_client = ENV.fetch('AWS_S3_MOCK_CLIENT', 'true') == 'true'
|
39
|
+
max_file_size = ENV.fetch('AWS_S3_MAX_FILE_SIZE', 1_048_576).to_i
|
40
|
+
storage_class = ENV.fetch('AWS_S3_STORAGE_CLASS', 'STANDARD')
|
41
|
+
keep_file_name = ENV.fetch('AWS_S3_KEEP_FILE_NAME', 'true') == 'true'
|
42
|
+
|
43
|
+
# Required arguments
|
44
|
+
arguments = {
|
45
|
+
file_path: ENV['FILE_PATH'],
|
46
|
+
cmk_key_id: ENV['CMK_KEY_ID'],
|
47
|
+
aws_s3_bucket: ENV['AWS_S3_BUCKET'],
|
48
|
+
aws_region: ENV['AWS_REGION'],
|
49
|
+
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
50
|
+
aws_access_key: ENV['AWS_ACCESS_KEY']
|
51
|
+
}
|
52
|
+
|
53
|
+
# Checks presence of required arguments and configures porky_lib
|
54
|
+
check_arguments(arguments)
|
55
|
+
setup_porky_lib(arguments, use_mock_client, max_file_size)
|
56
|
+
|
57
|
+
write_options = {
|
58
|
+
storage_class: storage_class,
|
59
|
+
file_name: (File.basename(arguments[:file_path]) if keep_file_name)
|
60
|
+
}.compact
|
61
|
+
|
62
|
+
# Creates CMK key with empty tags and stores file
|
63
|
+
PorkyLib::Symmetric.instance.create_key([{}], arguments[:cmk_key_id]) unless PorkyLib::Symmetric.instance.cmk_alias_exists?(arguments[:cmk_key_id])
|
64
|
+
file_key = PorkyLib::FileService.instance.write_file(arguments[:file_path], arguments[:aws_s3_bucket], arguments[:cmk_key_id], write_options)
|
65
|
+
|
66
|
+
puts "SUCCESS - Created file: '#{arguments[:file_path]}' bucket: '#{arguments[:aws_s3_bucket]}' file_key: '#{file_key}'"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def check_arguments(arguments)
|
73
|
+
nil_arguments = []
|
74
|
+
arguments.map { |key, value| nil_arguments.push(key.to_s.upcase) if value.nil? && !key.nil? }
|
75
|
+
abort "ERROR - Need to provide as environment variables: #{nil_arguments.join(', ')}" unless nil_arguments.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup_porky_lib(arguments, use_mock_client, max_file_size)
|
79
|
+
PorkyLib::Config.configure(aws_region: arguments[:aws_region],
|
80
|
+
aws_key_id: arguments[:aws_access_key_id],
|
81
|
+
aws_key_secret: arguments[:aws_access_key],
|
82
|
+
aws_client_mock: use_mock_client,
|
83
|
+
max_file_size: max_file_size)
|
84
|
+
PorkyLib::Config.initialize_aws
|
85
|
+
end
|
data/porky_lib.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency 'bundler'
|
26
26
|
spec.add_development_dependency 'bundler-audit'
|
27
27
|
spec.add_development_dependency 'byebug'
|
28
|
+
spec.add_development_dependency 'codacy-coverage'
|
28
29
|
spec.add_development_dependency 'codecov'
|
29
30
|
spec.add_development_dependency 'msgpack'
|
30
31
|
spec.add_development_dependency 'rake'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: porky_lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Fletcher
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-kms
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: codacy-coverage
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: codecov
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -390,6 +404,7 @@ files:
|
|
390
404
|
- lib/porky_lib/unencrypted.rb
|
391
405
|
- lib/porky_lib/unencrypted/file_service.rb
|
392
406
|
- lib/porky_lib/version.rb
|
407
|
+
- lib/tasks/file.rake
|
393
408
|
- porky_lib.gemspec
|
394
409
|
homepage: https://github.com/Zetatango/porky_lib
|
395
410
|
licenses: []
|
@@ -409,7 +424,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
409
424
|
- !ruby/object:Gem::Version
|
410
425
|
version: '0'
|
411
426
|
requirements: []
|
412
|
-
rubygems_version: 3.
|
427
|
+
rubygems_version: 3.1.2
|
413
428
|
signing_key:
|
414
429
|
specification_version: 4
|
415
430
|
summary: A library for cryptographic services using AWS KMS and RbNaCl
|