sym 2.8.1 → 3.0.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 (55) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +31 -30
  3. data/.envrc +7 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +150 -928
  6. data/.travis.yml +16 -26
  7. data/CHANGELOG.md +220 -167
  8. data/Gemfile +1 -0
  9. data/LICENSE +2 -2
  10. data/README.adoc +670 -0
  11. data/Rakefile +10 -4
  12. data/bin/changelog +34 -0
  13. data/bin/sym.completion.bash +6 -4
  14. data/bin/sym.symit.bash +412 -187
  15. data/codecov.yml +29 -0
  16. data/design/sym-class-dependency-future-refactor.png +0 -0
  17. data/design/sym-class-dependency-vertical.png +0 -0
  18. data/design/sym-class-dependency.graffle +0 -0
  19. data/design/sym-class-dependency.png +0 -0
  20. data/design/sym-help.png +0 -0
  21. data/exe/keychain +1 -1
  22. data/exe/sym +5 -2
  23. data/lib/ruby_warnings.rb +7 -0
  24. data/lib/sym.rb +2 -8
  25. data/lib/sym/app.rb +1 -2
  26. data/lib/sym/app/args.rb +3 -2
  27. data/lib/sym/app/cli.rb +34 -21
  28. data/lib/sym/app/cli_slop.rb +9 -2
  29. data/lib/sym/app/commands.rb +1 -1
  30. data/lib/sym/app/commands/base_command.rb +1 -1
  31. data/lib/sym/app/commands/bash_completion.rb +2 -2
  32. data/lib/sym/app/commands/open_editor.rb +1 -1
  33. data/lib/sym/app/commands/password_protect_key.rb +4 -4
  34. data/lib/sym/app/commands/show_examples.rb +1 -1
  35. data/lib/sym/app/input/handler.rb +7 -1
  36. data/lib/sym/app/keychain.rb +15 -9
  37. data/lib/sym/app/output/noop.rb +2 -1
  38. data/lib/sym/app/password/cache.rb +1 -1
  39. data/lib/sym/app/password/providers.rb +2 -3
  40. data/lib/sym/app/private_key/decryptor.rb +2 -2
  41. data/lib/sym/app/private_key/detector.rb +4 -7
  42. data/lib/sym/application.rb +6 -11
  43. data/lib/sym/constants.rb +39 -23
  44. data/lib/sym/data/wrapper_struct.rb +20 -12
  45. data/lib/sym/errors.rb +13 -2
  46. data/lib/sym/extensions/instance_methods.rb +7 -8
  47. data/lib/sym/extensions/stdlib.rb +0 -1
  48. data/lib/sym/extensions/with_retry.rb +1 -1
  49. data/lib/sym/extensions/with_timeout.rb +1 -1
  50. data/lib/sym/version.rb +54 -5
  51. data/sym.gemspec +36 -35
  52. metadata +102 -66
  53. data/.codeclimate.yml +0 -30
  54. data/README.md +0 -623
  55. data/lib/sym/app/password/providers/drb_provider.rb +0 -41
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sym
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-07 00:00:00.000000000 Z
11
+ date: 2020-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored2
@@ -56,60 +56,60 @@ dependencies:
56
56
  name: highline
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.7'
61
+ version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '1.7'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: coin
70
+ name: dalli
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 0.1.8
75
+ version: '0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 0.1.8
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: dalli
84
+ name: asciidoctor
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '2.7'
90
- type: :runtime
89
+ version: '0'
90
+ type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '2.7'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: codeclimate-test-reporter
98
+ name: aruba
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '1.0'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '1.0'
110
+ version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: simplecov
112
+ name: bundler
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: aruba
140
+ name: rake
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: bundler
154
+ name: relaxed-rubocop
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -165,7 +165,21 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: rake
168
+ name: rspec
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '3'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '3'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec-its
169
183
  requirement: !ruby/object:Gem::Requirement
170
184
  requirements:
171
185
  - - ">="
@@ -179,21 +193,35 @@ dependencies:
179
193
  - !ruby/object:Gem::Version
180
194
  version: '0'
181
195
  - !ruby/object:Gem::Dependency
182
- name: rspec
196
+ name: rubocop
183
197
  requirement: !ruby/object:Gem::Requirement
184
198
  requirements:
185
- - - "~>"
199
+ - - '='
186
200
  - !ruby/object:Gem::Version
187
- version: '3'
201
+ version: 0.81.0
188
202
  type: :development
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
- - - "~>"
206
+ - - '='
193
207
  - !ruby/object:Gem::Version
194
- version: '3'
208
+ version: 0.81.0
195
209
  - !ruby/object:Gem::Dependency
196
- name: rspec-its
210
+ name: simplecov
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: codecov
197
225
  requirement: !ruby/object:Gem::Requirement
198
226
  requirements:
199
227
  - - ">="
@@ -220,32 +248,38 @@ dependencies:
220
248
  - - ">="
221
249
  - !ruby/object:Gem::Version
222
250
  version: '0'
223
- description: "Sym is a ruby library (gem) that offers both the command line interface
224
- (CLI) and a set of rich Ruby APIs, which make it rather trivial to add encryption
225
- and decryption of sensitive data to your development or deployment flow. As a layer
226
- of additional security, you can encrypt the private key itself with a password.
227
- \ Unlike many other existing encryption tools, Sym focuses on getting out of the
228
- way by offering its streamlined interface, hoping to make encryption of application
229
- secrets nearly completely transparent to the developers. For the data encryption
230
- Sym uses a symmetric 256-bit key with the AES-256-CBC cipher, same cipher as used
231
- by the US Government. For password-protecting the key Sym uses AES-128-CBC cipher.
232
- The resulting data is zlib-compressed and base64-encoded. The keys are also base64
233
- encoded for easy copying/pasting/etc.\n \nSym accomplishes encryption transparency
234
- by combining convenience features: 1) Sym can read the private key from multiple
235
- source types, such as: a pathname to a file, an environment variable name, a keychain
236
- entry, or CLI argument. You simply pass either of these to the -k flag — one flag
237
- that works for all source types. 2) By utilizing OS-X Keychain on a Mac, Sym offers
238
- truly secure way of storing the key on a local machine, much more secure then storing
239
- it on a file system, 3) By using a local password cache (activated with -c) via
240
- an in-memory provider such as memcached or drb, sym invocations take advantage of
241
- password cache, and only ask for a password once per a configurable time period,
242
- 4) By using SYM_ARGS environment variable, where common flags can be saved. This
243
- is activated with sym -A, 5) By reading the key from the default key source file
244
- ~/.sym.key which requires no flags at all, 6) By utilizing the --negate option to
245
- quickly encrypt a regular file, or decrypt an encrypted file with extension .enc
246
- 7) By implementing the -t (edit) mode, that opens an encrypted file in your $EDITOR,
247
- and replaces the encrypted version upon save & exit, optionally creating a backup.
248
- 8) By offering the Sym::MagicFile ruby API to easily read encrypted files into memory.\n"
251
+ description: "\n Sym is a ruby library (gem) that offers both the command line interface
252
+ \n (CLI) and a set of rich Ruby APIs, which make it rather trivial to add \n encryption
253
+ and decryption of sensitive data to your development or deployment \n workflow.\n
254
+ \n For additional security the private key itself can be encrypted with a \n user-generated
255
+ password. For decryption using the key the password can be \n input into STDIN,
256
+ or be defined by an ENV variable, or an OS-X Keychain Entry. \n \n Unlike many other
257
+ existing encryption tools, Sym focuses on getting out of \n your way by offering
258
+ a streamlined interface with password caching (if \n MemCached is installed and
259
+ running locally) in hopes to make encryption of \n application secrets nearly completely
260
+ transparent to the developers. \n \n Sym uses symmetric 256-bit key encryption with
261
+ the AES-256-CBC cipher, \n same cipher as used by the US Government. \n \n For password-protecting
262
+ the key Sym uses AES-128-CBC cipher. The resulting \n data is zlib-compressed and
263
+ base64-encoded. The keys are also base64 encoded \n for easy copying/pasting/etc.\n
264
+ \n Sym accomplishes encryption transparency by combining several convenient features:\n
265
+ \ \n 1. Sym can read the private key from multiple source types, such as pathname,
266
+ \n an environment variable name, a keychain entry, or CLI argument. You simply
267
+ \n pass either of these to the -k flag one flag that works for all source
268
+ types.\n \n 2. By utilizing OS-X Keychain on a Mac, Sym offers truly secure way
269
+ of \n storing the key on a local machine, much more secure then storing it
270
+ on a file system,\n \n 3. By using a local password cache (activated with -c)
271
+ via an in-memory provider \n such as memcached, sym invocations take advantage
272
+ of password cache, and \n only ask for a password once per a configurable time
273
+ period, \n \n 4. By using SYM_ARGS environment variable, where common flags can
274
+ be saved. This \n is activated with sym -A,\n \n 5. By reading the key from
275
+ the default key source file ~/.sym.key which \n requires no flags at all,\n
276
+ \ \n 6. By utilizing the --negate option to quickly encrypt a regular file, or
277
+ decrypt \n an encrypted file with extension .enc\n \n 7. By implementing
278
+ the -t (edit) mode, that opens an encrypted file in your $EDITOR, \n and replaces
279
+ the encrypted version upon save & exit, optionally creating a backup.\n \n 8.
280
+ By offering the Sym::MagicFile ruby API to easily read encrypted files into memory.\n\nPlease
281
+ refer the module documentation available here:\nhttps://www.rubydoc.info/gems/sym\n
282
+ \n"
249
283
  email:
250
284
  - kigster@gmail.com
251
285
  executables:
@@ -255,8 +289,8 @@ extensions: []
255
289
  extra_rdoc_files: []
256
290
  files:
257
291
  - ".circleci/config.yml"
258
- - ".codeclimate.yml"
259
292
  - ".document"
293
+ - ".envrc"
260
294
  - ".gitignore"
261
295
  - ".rspec"
262
296
  - ".rubocop.yml"
@@ -265,15 +299,18 @@ files:
265
299
  - CHANGELOG.md
266
300
  - Gemfile
267
301
  - LICENSE
268
- - README.md
302
+ - README.adoc
269
303
  - Rakefile
270
304
  - SYM-CLI.md
305
+ - bin/changelog
271
306
  - bin/console
272
307
  - bin/setup
273
308
  - bin/sym.completion.bash
274
309
  - bin/sym.symit.bash
310
+ - codecov.yml
275
311
  - design/ascii-cinema.png
276
312
  - design/sym-class-dependency-future-refactor.png
313
+ - design/sym-class-dependency-vertical.png
277
314
  - design/sym-class-dependency.graffle
278
315
  - design/sym-class-dependency.pdf
279
316
  - design/sym-class-dependency.png
@@ -282,6 +319,7 @@ files:
282
319
  - design/sym-symit-help.png
283
320
  - exe/keychain
284
321
  - exe/sym
322
+ - lib/ruby_warnings.rb
285
323
  - lib/sym.rb
286
324
  - lib/sym/app.rb
287
325
  - lib/sym/app/args.rb
@@ -309,7 +347,6 @@ files:
309
347
  - lib/sym/app/output/stdout.rb
310
348
  - lib/sym/app/password/cache.rb
311
349
  - lib/sym/app/password/providers.rb
312
- - lib/sym/app/password/providers/drb_provider.rb
313
350
  - lib/sym/app/password/providers/memcached_provider.rb
314
351
  - lib/sym/app/private_key/base64_decoder.rb
315
352
  - lib/sym/app/private_key/decryptor.rb
@@ -351,16 +388,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
351
388
  requirements:
352
389
  - - ">="
353
390
  - !ruby/object:Gem::Version
354
- version: '2.2'
391
+ version: '2.3'
355
392
  required_rubygems_version: !ruby/object:Gem::Requirement
356
393
  requirements:
357
394
  - - ">="
358
395
  - !ruby/object:Gem::Version
359
396
  version: '0'
360
397
  requirements: []
361
- rubyforge_project:
362
- rubygems_version: 2.6.13
363
- signing_key:
398
+ rubygems_version: 3.1.4
399
+ signing_key:
364
400
  specification_version: 4
365
401
  summary: Dead-simple and easy to use encryption library on top of OpenSSL, offering
366
402
  rich Ruby API as well as feature-rich CLI able to generate a key, encrypt/decrypt
@@ -1,30 +0,0 @@
1
- ---
2
- engines:
3
- duplication:
4
- enabled: true
5
- config:
6
- languages:
7
- - ruby
8
- - javascript
9
- - python
10
- - php
11
- fixme:
12
- enabled: true
13
- rubocop:
14
- enabled: true
15
- checks:
16
- Rubocop/Metrics/MethodLength:
17
- enabled: false
18
- Rubocop/Metrics/CyclomaticComplexity:
19
- enabled: false
20
- ratings:
21
- paths:
22
- - "**.inc"
23
- - "**.js"
24
- - "**.jsx"
25
- - "**.module"
26
- - "**.php"
27
- - "**.py"
28
- - "**.rb"
29
- exclude_paths:
30
- - spec/
data/README.md DELETED
@@ -1,623 +0,0 @@
1
- # Sym — Light-weight Symmetric Encryption for Humans
2
-
3
- [![Gem Version](https://badge.fury.io/rb/sym.svg)](https://badge.fury.io/rb/sym)
4
- [![Sym Downloads](http://ruby-gem-downloads-badge.herokuapp.com/sym?extension=png)](https://rubygems.org/gems/sym)
5
-
6
- [![Build Status](https://travis-ci.org/kigster/sym.svg?branch=master)](https://travis-ci.org/kigster/sym)
7
- [![Code Climate](https://codeclimate.com/github/kigster/sym/badges/gpa.svg)](https://codeclimate.com/github/kigster/sym)
8
- [![Test Coverage](https://codeclimate.com/github/kigster/sym/badges/coverage.svg)](https://codeclimate.com/github/kigster/sym/coverage)
9
- [![Issue Count](https://codeclimate.com/github/kigster/sym/badges/issue_count.svg)](https://codeclimate.com/github/kigster/sym)
10
-
11
- **Discuss Sym on Gitter**:
12
-
13
- [![Gitter](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/kigster/sym)
14
-
15
- ---
16
-
17
- **March 10th, 2017**. Please checkout the post "**[Dead Simple Encryption with Sym](http://kig.re/2017/03/10/dead-simple-encryption-with-sym.html)**" that announces this library, and provides further in-depth discussion.
18
-
19
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FSFYYNEQ8RKWU)
20
-
21
- Your donation of absolutely any amount is very much appreciated.
22
-
23
- ---
24
-
25
- ## Description
26
-
27
- <div style="padding 40px; margin: 40px; font-size: 13pt;">
28
-
29
- <p><strong>sym</strong> is an open source command line utility and Ruby API which makes it very <em>easy to add reliable encryption and decryption</em> of sensitive data to an application or a project written in any language.</p>
30
-
31
- <p>Unlike many existing encryption tools, <strong>sym</strong> focuses on narrowing the gap between convenience and security, by offering enhanced usability and a streamlined ruby API and a CLI. The primary goal of the library is to make encryption very easy and transparent. </p>
32
-
33
- <p><strong>sym</strong> uses the <em><a href="https://en.wikipedia.org/wiki/Symmetric-key_algorithm">Symmetric Encryption</a></em> algorithm. This means that the same key is used to encrypt and decrypt data. In addition to the key, the encryption uses a randomized IV vector, which is automatically generated per each encryption and serialized with the data. Result of encryption is zlib-compressed, and base64 encoded, to be suitable for storage as string. The generated keys are also base64-encoded for convenience.</p>
34
-
35
- <p>Finally, the library offers encryption using any regular password, and in particular supports password-protected encryption keys. Automatic key detection algorithm attempts to resolve a provided key as a filename, an environment variable name, an OS-X Keychain password entry name, a key itself, or a default key file.</p>
36
-
37
- </div>
38
-
39
- ### Quick Demo of the CLI in Action
40
-
41
- [![asciicast](design/ascii-cinema.png)](https://asciinema.org/a/106737)
42
-
43
-
44
- #### Help Screens, Examples and Symit Bash Wrapper
45
-
46
- This may be a good time to take a look at the full help message for the `sym` tool, shown naturally with a `-h` or `--help` option. Examples can be shown with `-E/--examples` flag.
47
-
48
- Additionally, Sym comes with a helpful BASH wrapper `symit`.
49
-
50
- **Help screens for `sym` and `symit` are shown in full on another page — [Sym Help Screens and Symit](SYM-CLI.md). Please refer to it for complete help screens and the examples.**
51
-
52
-
53
- ## Supported Ruby Versions
54
-
55
- [![Build Status](https://travis-ci.org/kigster/sym.svg?branch=master)](https://travis-ci.org/kigster/sym)
56
-
57
- Sym currently builds and runs on the following ruby versions:
58
-
59
- * 2.2.5
60
- * 2.3.3
61
- * 2.4.1
62
- * jruby-9.1.7.0
63
-
64
- ### Motivation
65
-
66
- The main goal when writing this tool was to streamline and simplify handling of sensitive data in a trasparent and easy to use way without sacrificing security.
67
-
68
- Most common use-cases include:
69
-
70
- * __Encrypting/decrypting of application secrets files__, so that the encrypted secrets can be safely checked into the git repository and distributed, and yet without much of the added headache that this often requires
71
- * __Secure message transfer between any number of receipients__
72
- * __General purpose encryption/decryption with a 256-bit encryption key__, optionally itself re-encrypted with a password.
73
- * __General purpose encryption/decryption with an arbitrary password__.
74
-
75
- __Sym__ is a layer built on top of the [`OpenSSL`](https://www.openssl.org/) library, and, hopefully, makes encryption more accessible to every-day developers, QA, and dev-ops folks, engaged in deploying applications.
76
-
77
- ### What's Included
78
-
79
- This gem includes two primary components:
80
-
81
- 1. **[Rich command line interface CLI](#cli)** with many features to streamline encryption/decryption, and to be integrated into the deployment flow.<br /><br />
82
- 2. Ruby APIs:
83
- * **[Key Generation, Encryption & Decryption API](#rubyapi)**
84
- - is activated by including `Sym` module in a class, it adds easy to use `encr`/`decr` methods.
85
- * **[Application API to shadow the CLI usage](#rubyapi-app)**
86
- - You can instantiate `Sym::Application` class with a hash representing CLI arguments, and then call it's `#execute` method to mimic CLI execution.
87
- * **[Sym::MagicFile API](#magic-file)**
88
- - This is a convenience class allowing you to encrypt/decrypt files in your ruby code with just couple of lines of code.
89
- * **[Sym::Configuration](#rubyapi-config)**
90
- - Use this class to override the default cipher, and configure other parameters such as compression, password caching, and more.
91
-
92
- ### Massive Time Savers
93
-
94
- **Sym** tries very hard to get out of your way, to make it *feel* as if your encrypted files are as easy to work with as the unencrypted files. It accomplishes this transparency with the following features:
95
-
96
- * By using **Mac OS-X Keychain**, `sym` offers a simple yet secure way of storing the key on a local machine, much more secure then storing it on a file system.
97
- * By using a **password cache** (`-c`) via an in-memory provider such as `memcached` or `drb`, `sym` invocations take advantage of password cache, and only ask for a password once per a configurable time period.
98
- * By using **`SYM_ARGS` environment variable** you can save common flags and they will be applied whenever `-A` flag is activated.
99
- * By reading a key from the default key source file `~/.sym.key` which requires no flags at all.
100
- * By utilizing the **`--negate` option to quickly encrypt a regular file**, or decrypt an encrypted file with extension `.enc`.
101
- * By using the **`-t file` (edit) mode**, that opens an encrypted file in your `$EDITOR`, and replaces the encrypted version upon save & exit.
102
-
103
- As you can see, we really tried to build a tool that provides good security for application secrets, including password-based encryption, but does not annoyingly ask for password every time. With `--edit` option, and `--negate` options you can treat encrypted files like regular files.
104
-
105
- > Encrypting application secrets had never been easier! –– Socrates [LOL, -ed.]
106
-
107
- ## Using Sym
108
-
109
- #### Installation
110
-
111
- If you plan on using the library in your Ruby project with Bundler managing its dependencies, just include the following line in your `Gemfile`:
112
-
113
- gem 'sym'
114
-
115
- And then run `bundle`.
116
-
117
- Or install it into the global namespace with `gem install` command:
118
-
119
- $ gem install sym
120
- $ sym -h
121
- $ sym -E # see examples
122
-
123
- __BASH Completion__
124
-
125
- Optionally, after gem installation, you can also install bash-completion of gem's command line options, but running the following command (and feel free to use any of the "dot" files you prefer):
126
-
127
- sym -B ~/.bashrc
128
-
129
- Should you choose to install it (this part is optional), you will be able to use "tab-tab" after typing `sym`, and you'll be able to choose from all of the supported flags.
130
-
131
- #### Typical Use-Case Scenario
132
-
133
- 1. You generate a new encryption key, that will be used to both encrypt and decrypt the data. The key is 256 bits, or 32 bytes, or 45 bytes when base64-encoded, and can be generated with `sym -g`. The key must be saved somewhere for later retrieval. The key should not be easily accessible to an attacker. Note, that while generating the key, you can:
134
- * optionally password protect the key with `sym -gp`
135
- * save the key into a file with `sym -gpo key-file`
136
- * save it into the OS-X Keychain, with `sym -gpx keychain-name`
137
- * cache the password, with `sym -gpcx keychain-name`
138
- * Normally, `sym` will print the resulting key to STDOUT
139
- * You can prevent the key from being printed to STDOUT with `-q/--quiet`.
140
- 2. Next, let's assume you have a file or a string that you want to encrypt. We call this *data*.
141
- 3. In order to encrypt the __data__, we must supply an encryption key. Flag `-k` automatically retrieves the key, by trying to read it in several distinct ways, such as:
142
- * a file with a pathname specified by the argument (eg, `-k ~/.key`)
143
- * or environment variable (eg `-k ENC_KEY`)
144
- * or OS-X Keychain entry
145
- * verbatum string argument (not recommended)
146
- * alternatively, you can paste the key interactively with `-i` or save the default key in `~/.sym.key` file.
147
- 4. Finally, we are ready to encrypt. The data to be encrypted can be read from a file with `-f filename`, or it can be read from STDIN, or a passed on the command line with `-s string`. For example, `sym -e -k ~/.key -f /etc/passwd` will encrypt the file and print the encrypted contents to STDOUT.
148
- 4. Instead of printing to STDOUT, the output can be saved to a file with `-o <file>` or a simple redirect or a pipe.
149
- 5. Encrypted file can later be decrypted with `sym -d ...` assuming the same key it was encrypted with.
150
- 6. Encrypted file with extension `.enc` can be automatically decrypted with `-n/--negate file` option; if the file does not end with `.enc`, it is encrypted and `.enc` extension added to the resulting file.
151
- 7. With `-t/--edit file` flag you can edit an encrypted file in VIM (or `$EDITOR`) any encrypted file and edit it. Once you save it, the file gets re-encrypted and replaces the previous version. A backup can be created with `-b` option. See the section on [inline editing](#inline)
152
-
153
- A sample session that uses Mac OS-X Keychain to store the password-protected key.
154
-
155
- ```bash
156
- # Gen a new key, password-encrypt it, cache the password, save
157
- # result in the key chain entry 'my-new-key' (but don't print it '-q')
158
- ❯ sym -gpqcx my-new-key
159
- New Password : •••••••••
160
- Confirm Password : •••••••••
161
-
162
- ❯ sym -eck my-new-key -s 'My secret data' -o secret.enc
163
- Password: •••••••••
164
-
165
- ❯ cat secret.enc
166
- BAhTOh1TeW06OkRhdGE6OldyYXBFefDFFD.....
167
-
168
- ❯ sym -dck my-new-key -f secret.enc
169
- My secret data
170
-
171
- # Now, let's save our keychain key in the default key file:
172
- ❯ sym -ck my-new-key -o ~/.sym.key
173
- # Now we can decrypt/encrypt with this key at will
174
- ❯ sym -n secret.enc
175
- # created a decrypted file `secret`
176
-
177
- # Lets now save common flags in the SYM_ARGS bash variable:
178
- ❯ export SYM_ARGS="-ck my-new-key"
179
- ❯ sym -df secret.enc
180
- My secret data
181
- ```
182
-
183
- Note that password caching is off by default, but is enabled with `-c` flag. In the example above, the decryption step fetched the password from the cache, and so the user was not required to re-enter the password.
184
-
185
- <a name="inline"></a>
186
-
187
- #### Inline Editing of Encrypted Files
188
-
189
- The `sym` CLI tool supports one particularly interesting mode, that streamlines handling of encrypted files. The mode is called __edit mode__, and is activated with the `-t` flag.
190
-
191
- Instead of decrypting data anytime you need to change it into a new file and then manually re-encrypting the result, you can use the shortcut flag `-t` (for "edi**t**"), which decrypts your data into a temporary file, automatically opening it with an `$EDITOR`.
192
-
193
- sym -t config/application/secrets.yml.enc -k ~/.key
194
-
195
- > This is one of those time-saving features that can make a difference in making encryption feel easy and transparent.
196
-
197
- > NOTE: this mode does not seem to work with GUI editors such as Atom or TextMate. Since `sym` waits for the editor process to complete, GUI editors "complete" immediately upon starting a windowed application.
198
-
199
- In this mode several flags are of importance:
200
-
201
- -b (--backup) – will create a backup of the original file
202
- -v (--verbose) - will show additional info about file sizes
203
-
204
- Here is a full command that opens a file specified by `-f | --file`, using the key specified in `-k | --keyfile`, in the editor defined by the `$EDITOR` environment variable (or if not set – defaults to `/bin/vi`)".
205
-
206
- Example: here we edit an encrypted file in `vim`, while using interactive mode to paste the key (`-i | --interactive`), and then creating a backup file (`-b | --backup`) upon save:
207
-
208
- sym -ibt data.enc
209
- # => Private Key: ••••••••••••••••••••••••••••••••••••••••••••
210
- #
211
- # => Diff:
212
- # 3c3
213
- # # (c) 2015 Konstantin Gredeskoul. All rights reserved.
214
- # ---
215
- # # (c) 2016 Konstantin Gredeskoul. All rights reserved.
216
-
217
- Note the `diff` shown after save.
218
-
219
- <a name="rubyapi"></a>
220
-
221
- ## Ruby API
222
-
223
- ### Including `Sym` module
224
-
225
- Low-level encryption routines can be imported by including `Sym` module into your class or a module. Such class will be decorated with new class methods `#private_key` and `#create_private_key`, as well as instance methods `#encr`, and `#decr`.
226
-
227
- #### Class Method `#create_private_key()`
228
-
229
- This method will generate a new key each time it's called.
230
-
231
- #### Class Method `#private_key(value = nil)`
232
-
233
- This method will either assign an existing key (if a value is passed) or generate and save a new key in the class instance variable. Therefore each class including `Sym` will (by default) use a unique key (unless the key is passed in as an argument).
234
-
235
- The following example illustrates this point:
236
-
237
- ```ruby
238
- require 'sym'
239
-
240
- class TestClass
241
- include Sym
242
- end
243
-
244
- @key = TestClass.create_private_key
245
- @key.eql?(TestClass.private_key) # => false
246
- # A new key was created and saved in #private_key accessor.
247
-
248
- class SomeClass
249
- include Sym
250
- private_key TestClass.private_key
251
- end
252
-
253
- @key.eql?(SomeClass.private_key) # => true (it was assigned)
254
- ```
255
-
256
- #### Encrypting and Decrypting
257
-
258
- So how would we use this library from another Ruby project to encrypt and decrypt values?
259
-
260
- After including the `Sym` module, two instance methods are added:
261
-
262
- * `#encr(value, private_key)` and
263
- * `#decr(value, private_key)`.
264
-
265
- Therefore you could write something like this below, protecting a sensitive string using a class-level secret.
266
-
267
- ```ruby
268
- require 'sym'
269
- class TestClass
270
- include Sym
271
- private_key ENV['SECRET']
272
-
273
- def sensitive_value=(value)
274
- @sensitive_value = encr(value, self.class.private_key)
275
- end
276
- def sensitive_value
277
- decr(@sensitive_value, self.class.private_key)
278
- end
279
- end
280
- ```
281
-
282
- #### Encrypting the Key Itself
283
-
284
- You can encrypt the private key using a custom password. This is highly recommended, because without the password the key is the only piece that stands between an attacker and decrypting your sensitive data.
285
-
286
- For this purpose, two more instance methods exist:
287
-
288
- * `#encr_password(data, password, iv = nil)`
289
- * `#decr_password(encrypted_data, password, iv = nil)`
290
-
291
- They can be used independently of `encr` and `decr` to encrypt/decrypt any data with a password.
292
-
293
- <a name="magic-file"></a>
294
-
295
- ### Using `Sym::MagicFile` API for Reading/Writing Encrypted/Decrypted data
296
-
297
- This is probably the easiest way to leverage Sym-encrypted files in your application — by loading them into memory with `Sym::MagicFile`. This class provides a very simple API while supporting all of the convenience features of the rich application API (see below).
298
-
299
- You instantiate `Sym::MagicFile` with just two parameters: a `pathname` to a file (encrypted
300
- or not), and the `key` identifier. The identifier can either be a filename, or
301
- OS-X Keychain entry, or environment variable name, etc — basically it is resolve
302
- like any other `-k <value>` CLI flag.
303
-
304
- The following methods are available:
305
-
306
- * `#encrypt` — returns an encrypted string representing the encrypted contents ofa file specified by the pathname.
307
- * `#decrypt` — returns a decrypted string representing the decrypted contents of a file specified by the pathname.
308
- * `#encrypt_to(filename)` — encrypts the contents of a file specified by the pathname, and writes the result to a `filename`.
309
- * `#decrypt_to(filename)` — decrypts the contents of a file specified by the pathname, and writes the result to a `filename`.
310
-
311
- #### Example: Using `Sym::MagicFile` with the `RailsConfig` (or `Settings`) gem
312
-
313
- In this example, we assume that the environment variable `$PRIVATE_KEY` contain
314
- the key to be used in decryption.
315
-
316
- ```ruby
317
- require 'sym/magic_file'
318
- require 'yaml'
319
- secrets = Sym::MagicFile.new('/usr/local/etc/secrets.yml.enc', 'PRIVATE_KEY')
320
- hash = YAML.load(secrets.decrypt)
321
- ```
322
-
323
- Let's say that you are using [RailsConfig](https://github.com/railsconfig/config) gem for managing your Rails application setings. Since the gem allows appending settings from a hash, you can simply do the following in your `settings_initializer.rb`, and after all of the unencrypted settings are loaded:
324
-
325
- ```ruby
326
- require 'config'
327
- require 'sym/magic_file'
328
- require 'yaml'
329
- Settings.add_source!(
330
- YAML.load(
331
- Sym::MagicFile.new(
332
- '/usr/local/etc/secrets.yml.enc',
333
- 'PRIVATE_KEY'
334
- ).decrypt)
335
- )
336
- Settings.reload!
337
- ```
338
-
339
- <a name="rubyapi-app"></a>
340
-
341
- ### Using `Sym::Application` API
342
-
343
- Since the command line interface offers much more than just encryption/decryption of data with a key, majority of these features are available through `Sym::Application` instance.
344
-
345
- The class is instantiated with a hash that would be otherwise generated by parsing CLI arguments, typical `options`. For example, to generate the key, pass `generate: true` — essentially any flag in it's long form can be converted into a hash member.
346
-
347
- Here is an example:
348
-
349
- ```ruby
350
- require 'sym/application'
351
-
352
- key = Sym::Application.new(generate: true).execute
353
- # => '75ngenJpB6zL47/8Wo7Ne6JN1pnOsqNEcIqblItpfg4='
354
- ```
355
-
356
- ### Ruby API Conclusion
357
-
358
- Using `Sym`'s rich ruby API you can perform both low-level encryption/decryption, as well as high-level management of encrypted files. By using `Sym::MagicFile` and/or `Sym::Application` classes you can access the entire set of functionality expressed vi the CLI, described in details below.
359
-
360
- <a name="cli"></a>
361
- ## Using `sym` with the Command Line
362
-
363
- ### Encryption Keys
364
-
365
- The private key is the cornerstone of the symmetric encryption. Using `sym`, the key can be:
366
-
367
- * generated and printed to STDOUT, or saved to Mac OS-X KeyChain or a file
368
- * fetched from the Keychain in subsequent operations
369
- * password-protected during generation (or import) with the `-p` flag.
370
- * password can be cached using either `memcached` or `dRB` server, if the `-c` flag is provided.
371
- * must be kept very well protected and secure from attackers.
372
-
373
- The __unencrypted private__ key will be in the form of a base64-encoded string, 45 characters long.
374
-
375
- __Encrypted (with password) private key__ will be considerably longer, perhaps 200-300 characters long.
376
-
377
- #### Generating the Key — Examples
378
-
379
- ```bash
380
- # Let's generate a new key, and copy it to the clipboard (using `pbcopy` command on Mac OS-X):
381
- $ sym -g | pbcopy
382
-
383
- # Or save a new key into a bash variable
384
- $ KEY=$(sym -g)
385
-
386
- # Or save it to a file:
387
- $ sym -go ~/.key
388
-
389
- # Or create a password-protected key (`-p`), and save it to a file (`-o`),
390
- # cache the password (`-c`), and don't print the new key to STDOUT (`-q` for quiet)
391
- $ sym -gpcqo ~/.secret
392
- New Password: ••••••••••
393
- Confirm Password: ••••••••••
394
- $
395
- ```
396
-
397
- #### Resolving the `-k` Argument
398
-
399
- You can use the generated private key by passing an argument to the `-k` flag.
400
-
401
- **Sym** attempts to automatically resolve the key source by trying each of the following options, and then moving on to the next until the key is found, or error is shown:
402
-
403
- 1. the `-k value` flag, where the *value* is one of:
404
- * a file path, eg (`-k ~/.key`)
405
- * an environment variable name (`-k MY_KEY`)
406
- * an actual base64-encoded key (not recommended for security reasons)
407
- * a keychain name (`-k keychain-entry-name`)
408
- 2. pasting or typing the key with the `-i` (interactive) flag
409
- 3. if exists, a default key file, located in your home folder: `~/.sym.key` is used only when no other key-specifying flags were passed in.
410
-
411
- #### Encryption and Decryption
412
-
413
- <a name="inline"></a>
414
-
415
- #### Inline Editing
416
-
417
- The `sym` CLI tool supports one particularly interesting mode, that streamlines handling of encrypted files. The mode is called __edit mode__, and is activated with the `-t file` flag.
418
-
419
- In this mode `sym` will automaticaly decrypt the encrypted file into a temporary file, and then open it in `$EDITOR`. Once you quit the editor, `sym` will automatically diff the new and old content, and if it is different, `sym` will re-encrypt the new contents and overwrite the original file. You can create an optional backup by adding `-b` flag.
420
-
421
- > NOTE: this mode does not seem to work with GUI editors such as Atom or TextMate. Since `sym` waits for the editor process to complete, GUI editors "complete" immediately upon starting a windowed application.
422
- In this mode several flags are of importance:
423
-
424
- -b (--backup) – will create a backup of the original file
425
- -v (--verbose) - will show additional info about file sizes
426
-
427
- Here is a full command that opens a file specified by `-t | --edit file`, using the key specified in `-k | --keyfile`, in the editor defined by the `$EDITOR` environment variable (or if not set – defaults to `/bin/vi`)".
428
-
429
- To edit an encrypted file in `$EDITOR`, while asking to paste the key (`-i | --interactive`), while creating a backup file (`-b | --backup`):
430
-
431
- sym -tibf data.enc
432
- # => Private Key: ••••••••••••••••••••••••••••••••••••••••••••
433
- #
434
- # => Diff:
435
- # 3c3
436
- # # (c) 2015 Konstantin Gredeskoul. All rights reserved.
437
- # ---
438
- # # (c) 2016 Konstantin Gredeskoul. All rights reserved.
439
-
440
-
441
- #### Using KeyChain Access on Mac OS-X
442
-
443
- KeyChain storage is a huge time saver. It allows you to securely store the key the keychain, meaning the key can not be easily extracted by an attacker without a login to your account. Just having access to the disk is not enough.
444
-
445
- Apple had released a `security` command line tool, which this library uses to securely store a key/value pair of the key name and the actual private key in your OS-X KeyChain. The advantages of this method are numerous:
446
-
447
- * The private key won't be lying around your file system unencrypted, so if your Mac is ever stolen, you don't need to worry about the keys running wild.
448
- * If you sync your keychain with the iCloud you will have access to it on other machines
449
-
450
- As mentioned previously, to add the key to the KeyChain on the Mac, use `-x <key-name>` flag with `-g` flag when generating a key. The `key name` is what you call this particular key, based on how you plan to use it. For example, you may call it `staging`, etc.
451
-
452
- The following command generates the private key and immediately stores it in the KeyChain access under the name provided:
453
-
454
- sym -gx staging # the key is passwordless
455
- sym -gpcx staging # this key is password protected, with the password cached
456
-
457
- Next, whenever you need to *use* this key, you can specify the key with `-k staging`.
458
-
459
- Finally, you can delete a key from KeyChain access by running:
460
-
461
- keychain <name> delete
462
-
463
- Below we describe the purpose of the executable `keychain` shipped with sym.
464
-
465
- #### KeyChain Key Management
466
-
467
- `keychain` is an additional executable installed with the gem, which can be used to read (find), update (add), and delete keychain entries used by `sym`.
468
-
469
- It's help message is self-explanatory:
470
-
471
- Usage: keychain <name> [ add <contents> | find | delete ]
472
-
473
- #### Moving a Key to the Keychain
474
-
475
- You can easily move an existing key from a file or a string to a keychain by combining -k or -k to read the key, with -x to write it.
476
-
477
- sym -k $keysource -x mykey
478
-
479
- #### Adding Password to Existing Key
480
-
481
- You can add a password to a key by combining one of the key description flags (-k, -i) and then also -p. Use `-q` to hide new key from the STDOUT, and `c` to cache the password.
482
-
483
- sym -k $mykey -pqcx moo
484
-
485
- The above example will take an unencrypted key passed in `$mykey`, ask for a password and save password protected key into the keychain with name "moo."
486
-
487
- #### Password Caching
488
-
489
- Nobody likes to re-type passwords over and over again, and for this reason *Sym* supports password caching via either a locally running `memcached` instance (the default, if available), or a locally started `dRB` (distributed Ruby) server based on the `Coin` gem.
490
-
491
- Specifics of configuring both Cache Providers is left to the `Configuration` class, an example of which is shown below in the Ruby API section.
492
-
493
- In order to control password caching, the following flags are available:
494
-
495
- * `-c` turns on caching
496
- * `-u seconds` sets the expiration for cached passwords
497
- * `-r memcached | drb` controls which of the providers is used. Without this flag, *sym* auto-detects caching provider by first checking for `memcached`, and then starting the `dRB` server.
498
-
499
- #### Saving Common Flags in an Environment Variable
500
-
501
- You can optionally store frequently used flags for `sym` in the `SYM_ARGS` environment variable. For example, to always cache passwords, and to always use the same encryption key from the keychain named "production", set the following in your `~/.bashrc`:
502
-
503
- ```
504
- export SYM_ARGS="-cx production"
505
- ```
506
-
507
- This will be automatically appended to the command line if the `-A/--sym-args` flag is provided, and so to encrypt/decrypt anything with password caching enabled and using that particular key, you would simply type:
508
-
509
- ```bash
510
- # -cx production are added from SYM_ARGS
511
- sym -Aef file -o file.enc
512
-
513
- # And to decrypt:
514
- sym -Adf file.enc -o file.original
515
-
516
- # Or edit the encrypted file:
517
- sym -Atf file.enc
518
- ```
519
-
520
- ## Fine Tuning
521
-
522
- <a name="rubyapi-config"></a>
523
-
524
- ### Configuration
525
-
526
- The library contains a `Sym::Configuration` singleton class, which can be used to tweak some of the internals of the gem. Its meant for advanced users who know what they are doing. The code snippet shown below is an actual default configuration. You can override the defaults by including a similar snipped in your application initialization, right after the `require 'sym'`. The `Configuration` class is a Singleton, so changes to it will propagate to any subsequent calls to the gem.
527
-
528
- ```ruby
529
- require 'zlib'
530
- require 'sym'
531
- Sym::Configuration.configure do |config|
532
- config.password_cipher = 'AES-128-CBC'
533
- config.data_cipher = 'AES-256-CBC'
534
- config.private_key_cipher = config.data_cipher
535
- config.compression_enabled = true
536
- config.compression_level = Zlib::BEST_COMPRESSION
537
- config.encrypted_file_extension = 'enc'
538
- config.default_key_file = "#{ENV['HOME']}/.sym.key"
539
-
540
- config.password_cache_timeout = 300
541
-
542
- # When nil is selected, providers are auto-detected.
543
- config.password_cache_default_provider = nil
544
- config.password_cache_arguments = {
545
- # Ruby dRB-based in-memory cache.
546
- drb: {
547
- opts: {
548
- uri: 'druby://127.0.0.1:24924'
549
- }
550
- },
551
- # Memcached Provider – local is the default, but can be changed.
552
- memcached: {
553
- args: %w(127.0.0.1:11211),
554
- opts: { namespace: 'sym',
555
- compress: true,
556
- expires_in: config.password_cache_timeout
557
- }
558
- }
559
- }
560
- end
561
-
562
- ```
563
-
564
- As you can see, it's possible to change the default cipher type, although not all ciphers will be code-compatible with the current algorithm, and may require additional code changes.
565
-
566
-
567
- #### Encryption Features & Cipher
568
-
569
- The `sym` executable as well as the Ruby API provide:
570
-
571
- * Symmetric data encryption with:
572
- * the Cipher `AES-256-cBC` used by the US Government
573
- * 256-bit private key, that
574
- * can be generated and is a *base64-encoded* string about 45 characters long. The *decoded* key is always 32 characters (or 256 bytes) long.
575
- * can be optionally password-encrypted using the 128-bit key, and then be automatically detected (and password requested) when the key is used
576
- * can optionally have its password cached for 15 minutes locally on the machine using `memcached` or using a `dRB` server
577
- * Rich command line interface with some innovative features, such as inline editing of an encrypted file, using your favorite `$EDITOR`.
578
- * Data handling:
579
- * Automatic compression of the data upon encryption
580
- * Automatic base64 encryption to make all encrypted strings fit onto a single line.
581
- * This makes the format suitable for YAML or JSON configuration files, where only the values are encrypted.
582
- * Rich Ruby API
583
- * (OS-X Only): Ability to create, add and delete generic password entries from the Mac OS-X KeyChain, and to leverage the KeyChain to store sensitive private keys.
584
-
585
- ## Development
586
-
587
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
588
-
589
- To install this gem onto your local machine, run `bundle exec rake install`.
590
-
591
- To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
592
-
593
- #### Contributing
594
-
595
- Bug reports and pull requests are welcome on GitHub at [https://github.com/kigster/sym](https://github.com/kigster/sym)
596
-
597
- ### License
598
-
599
- **Sym** library is &copy; 2016-2017 Konstantin Gredeskoul.
600
-
601
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). The library is designed to be a layer on top of [`OpenSSL`](https://www.openssl.org/), distributed under the [Apache Style license](https://www.openssl.org/source/license.txt).
602
-
603
- ### Acknowledgements
604
-
605
- * The blog post [(Symmetric) Encryption With Ruby (and Rails)](http://stuff-things.net/2015/02/12/symmetric-encryption-with-ruby-and-rails/) provided the inspiration for this gem.
606
- * We'd like to thank [Spike Ilacqua](http://stuff-things.net/spike/), the author of the [strongbox](https://github.com/spikex/strongbox) gem, for providing very easy-to-read code examples of symmetric encryption.
607
- * We'd like to thank [Wissam Jarjoui](https://github.com/bosswissam) for support and inspiration, as well as testing of the early versions of this gem.
608
-
609
-
610
- #### Contributors:
611
-
612
- Contributions of any kind are very much welcome from anyone.
613
-
614
- Any pull requests will be reviewed promptly.
615
-
616
- Please submit feature requests, bugs, or donations :)
617
-
618
- * [Konstantin Gredeskoul](http:/kig.re) (primary developer)
619
- * [Wissam Jarjoui](https://github.com/bosswissam) (testing, inspiration)
620
- * [Megan Mathews](https://github.com/meganmmathews) (UX, CLI suggestions)
621
- * [Barry Anderson](https://twitter.com/z3ndrag0n) (sanity checking, review)
622
-
623
-