secrets-cipher-base64 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +25 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +1156 -0
  6. data/.travis.yml +13 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE +22 -0
  9. data/MANAGING-KEYS.md +67 -0
  10. data/README.md +314 -0
  11. data/Rakefile +13 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/exe/keychain +38 -0
  15. data/exe/secrets +8 -0
  16. data/lib/secrets.rb +73 -0
  17. data/lib/secrets/app.rb +42 -0
  18. data/lib/secrets/app/cli.rb +197 -0
  19. data/lib/secrets/app/commands.rb +27 -0
  20. data/lib/secrets/app/commands/command.rb +55 -0
  21. data/lib/secrets/app/commands/delete_keychain_key.rb +15 -0
  22. data/lib/secrets/app/commands/encrypt_decrypt.rb +22 -0
  23. data/lib/secrets/app/commands/generate_key.rb +41 -0
  24. data/lib/secrets/app/commands/open_editor.rb +90 -0
  25. data/lib/secrets/app/commands/show_examples.rb +63 -0
  26. data/lib/secrets/app/commands/show_help.rb +13 -0
  27. data/lib/secrets/app/commands/show_version.rb +13 -0
  28. data/lib/secrets/app/keychain.rb +136 -0
  29. data/lib/secrets/app/outputs/to_file.rb +27 -0
  30. data/lib/secrets/app/outputs/to_stdout.rb +11 -0
  31. data/lib/secrets/app/password_handler.rb +39 -0
  32. data/lib/secrets/cipher_handler.rb +45 -0
  33. data/lib/secrets/configuration.rb +23 -0
  34. data/lib/secrets/data.rb +23 -0
  35. data/lib/secrets/data/decoder.rb +24 -0
  36. data/lib/secrets/data/encoder.rb +24 -0
  37. data/lib/secrets/data/wrapper_struct.rb +43 -0
  38. data/lib/secrets/errors.rb +27 -0
  39. data/lib/secrets/extensions/class_methods.rb +12 -0
  40. data/lib/secrets/extensions/instance_methods.rb +110 -0
  41. data/lib/secrets/version.rb +3 -0
  42. data/secrets-cipher-base64.gemspec +33 -0
  43. metadata +243 -0
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ env:
3
+ - CODECLIMATE_REPO_TOKEN=be1a1a266b0ffc81fa0bd1e432a229f2a4ab420dcb9e9e15c1e75e2acad573b7
4
+ rvm:
5
+ - 2.2.5
6
+ - 2.3.1
7
+ script: "bundle exec rspec"
8
+ notifications:
9
+ email:
10
+ recipients:
11
+ - kigster@gmail.com
12
+ on_success: change
13
+ on_failure: always
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in secrets-cipher-base64.gemspec
4
+ gemspec
5
+
6
+ gem 'ffi', :platforms => [:mswin, :mingw]
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2016 Konstantin Gredeskoul, all rights reserved.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ # Managing Private Keys
2
+
3
+ In this document we discuss several methods of keeping the private keys safe and yet conveniently available when needed. We also note the possible security implications of each method.
4
+
5
+ We assume that you have some data or files that have been previously encrypted with a 32-byte key using this library, and that you want to be able to access the data easily with your private key, but at the same time not make it too easy for an attacker to find the keys.
6
+
7
+ ## Method 1.<br>Keychain Access on Mac OS-X
8
+
9
+ How you store the secret, is up to you, but here is one way that leverages Mac OS-X Keychain. In fact you can store multiple keys if you like. In the example below we'll store two separate keys, one for staging and one for production:
10
+
11
+ In your terminal, type these two commands. Note that the `-s` parameter is something you might want to customize, and make it easy to find. For example, instead of using `production` you could use `big-corp-django-secret-production`. The name should be such that it's easy to find once you open KeyChain Editor later.
12
+
13
+ ```bash
14
+ security add-generic-password -a $USER -D "secret-cipher-base64" -s "staging"
15
+ security add-generic-password -a $USER -D "secret-cipher-base64" -s "production"
16
+ ```
17
+
18
+ This step does not actually store any key, it simply creates a KeyChain placeholder for it. We'll generate and add the key next.
19
+
20
+ Finally, to make this a bit more efficient, I recommend listing the key names in an array-type environment variable set in your `~/.bashrc` file, for example:
21
+
22
+ ```bash
23
+ # ~/.bashrc
24
+ declare -a secret_names=(production staging)
25
+ ```
26
+
27
+ After declaring this array, you can even rewrite the above command as a loop, which could be handy if you are storing not 2 or 3 but 10+ keys.
28
+
29
+ ```bash
30
+ for secret_name in ${secret_names[@]}; do
31
+ security add-generic-password -a $USER \
32
+ -D "secret-cipher-base64" -s $secret_name
33
+ done
34
+ ```
35
+
36
+ ### Saving the Secret to KeyChain
37
+
38
+ * Open `KeyChain Access` application
39
+ * Search for the token you specified, for example `production`
40
+ * Double-click on the matching entry
41
+ * Click "Show password"
42
+ * Paste the copied value in that field
43
+ * Click "Save Changes"
44
+ * Repeat for `staging` or any other key you want to save.
45
+
46
+ ### Retrieving Secret from the KeyChain
47
+
48
+ Using the below bash function, you can retrieve and export the secrets as environment variables, which can later be read by your code:
49
+
50
+ ```bash
51
+ # append this function to your ~/.bashrc or ~/.bash_profile
52
+ function load_keys() {
53
+ declare -a secret_names=(production staging)
54
+ for secret_name in ${secret_names[@]}; do
55
+ varname="secret_${secret_name}" # eg, $secret_production
56
+ secret=`security find-generic-password -g -a $USER -w -D "secret-cipher-base64" -s "$secret_name"`
57
+ eval "export $varname=$secret"
58
+ done
59
+ }
60
+ ```
61
+
62
+ With this out of the way, we just need to type `load_keys` in Terminal to get our keys automatically exported.
63
+
64
+ ### Security
65
+
66
+ In this model, an attacker who obtains login access to your account will be able to quickly examine the local environment to discover one or more private keys already exported.
67
+
@@ -0,0 +1,314 @@
1
+ # Secrets-Cipher-Base64
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/secrets-cipher-base64.svg)](https://badge.fury.io/rb/secrets-cipher-base64)
4
+ [![Downloads](http://ruby-gem-downloads-badge.herokuapp.com/secrets-cipher-base64?type=total)](https://rubygems.org/gems/secrets-cipher-base64)
5
+
6
+ <br />
7
+
8
+ [![Build Status](https://travis-ci.org/kigster/secrets-cipher-base64.svg?branch=master)](https://travis-ci.org/kigster/secrets-cipher-base64)
9
+ [![Code Climate](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/gpa.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64)
10
+ [![Test Coverage](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/coverage.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64/coverage)
11
+ [![Issue Count](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/issue_count.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64)
12
+
13
+ ## Summary
14
+
15
+ What? *Another security gem?* —— Well, funny you should ask!
16
+
17
+ You see, security is an incredibly wide topic. The tools around security tend to fall into two classes: swiss army knife wrappers around `OpenSSL`, and more specialized tools. This gem falls in the second category. It wraps a very small part of `OpenSSL` library.
18
+
19
+ > __Namely, `secrets-cipher-base64` provides:__
20
+ >
21
+ > * Symmetric data encryption with:
22
+ > * the cipher `AES-256-CBC`
23
+ > * 256-bit private key
24
+ > * which can be optionally password-encrypted.
25
+ > * Rich command line interface with some innovative features, such as inline encrypted file editing using your current `$EDITOR`
26
+ > * Automatic compression of the data
27
+ > * Rich Ruby API and highly extensible approach to encryption/decryption
28
+ > * Automatic detection of password-protected keys,
29
+ > * and more...
30
+
31
+ The main point behind this gem is to allow you to store sensitive application secrets in your source code repo as `AES-256-CBC`-encrypted files or strings (this is the same encryption algorithm that US Government uses internally). The output of the encryption is always a (urlsafe) `base64`-encoded string, without the linebreaks.
32
+
33
+ The private key (encrypted or not) is also a base64-encoded string, typically 45 characters long (unless it's password encrypted, in which case it is considerably longer).
34
+
35
+ Using a single-line string that `urlsafe_encode64()` generates, makes this gem well suited for encrypting specific fields in the YAML file, or simply the entire file. This also means that the private key can be easily exported as an environment variable (as it's value is a single-line string).
36
+
37
+ > NOTE: The library leverages the code shown in the following discussion: http://stuff-things.net/2015/02/12/symmetric-encryption-with-ruby-and-rails/ I'd like to acknowledge the the author of the above thread for providing clear examples of a simple symmetric encryption with `OpenSSL`.
38
+
39
+ ## Symmetric Encryption
40
+
41
+ Symmetric encryption simply means that we are using the same private key to encrypt and decrypt. The secret can be generated by the tool and is a *base64-encoded* string which is 45 characters long. The *decoded* secret is always 32 characters long (or 256 bytes long).
42
+
43
+ In addition to the private key, the encryption uses an IV vector. The library completely hides `iv` from the user, generates one random `iv` per encryption, and stores it together with the field itself (*base64-encoded*).
44
+
45
+ ## Installation
46
+
47
+ If you plan on using the library in your ruby project with Bundler managing its dependencies, just include the following line in your `Gemfile`:
48
+
49
+ ```ruby
50
+ gem 'secrets-cipher-base64'
51
+ ```
52
+ And then run `bundle`.
53
+
54
+ Or install it into the global namespace with `gem install` command:
55
+
56
+ $ gem install secrets-cipher-base64
57
+ $ secrets -h
58
+ $ secrets -E # see examples
59
+
60
+ ## Usage
61
+
62
+ ### Private Keys
63
+
64
+ This library relies on the existance of the 32-byte private key (aka, *a secret*), that must be stored somewhere safely if your encrypted data is to be persisted, for example it can be saved into the keychain on Mac OSX.
65
+
66
+ > In fact, we put together a separate file that discusses strategies for protecting your encryption keys, for example you can read about [how to use Mac OS-X Keychain Access application](https://github.com/kigster/secrets-cipher-base64/blob/master/MANAGING-KEYS.md) and other methods. Additions and discussion are welcome. Please contribute!
67
+
68
+ You can use one key for all encrypted fields, or many keys – perhaps one per deployment environment, etc. While you can have per-field secrets, it seems like an overkill.
69
+
70
+ __NOTE: it is considered a bad practice to check in the private key into the version control.__ If you keep your secret out of your repo, you can check-in encrypted secrets file directly into the repo. As long as the private key itself is safe, the data in your encrypted will be next to impossible to extract.
71
+
72
+ ### Command Line (CLI)
73
+
74
+ You can generate using the command line, or in a programmatic way. First we'll discuss the command line usage, and in a later section we'll discuss Ruby API provided by the gem.
75
+
76
+ #### Generating and Using Private Keys
77
+
78
+ Once the gem is installed you will be able to run an executable `secrets`. Now let's generate and copy the new private key to the clipboard. Clipboard copy is activated with the -c flag:
79
+
80
+ secrets -gc
81
+
82
+ Or save a new key into a bash variable
83
+
84
+ SECRET=$(secrets -g)
85
+
86
+ Or save it to a file:
87
+
88
+ secrets -go ~/.key
89
+
90
+ Or create a password-protected key, and save it to a file:
91
+
92
+ secrets -gcp -o ~/.secret
93
+ # New Password: ••••••••••
94
+ # Confirm Password: ••••••••••
95
+
96
+ You can subsequently use the private key by either:
97
+
98
+ 1. passing the `-k [key value]` flag
99
+ 2. passing the `-K [key file]` flag
100
+
101
+ #### Using KeyChain Access on Mac OS-X
102
+
103
+ On Mac OS-X there is a third option – using the Keychain Access Manager behind the scenes. Apple 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:
104
+
105
+ * 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.
106
+ * If you sync your keychain with iCloud you will have access to it on other machines
107
+
108
+ To activate the KeyChain mode on the Mac, use `-x <keyname>` field instead of `-k` or `-K`, and add it to `-g` when generating a key. The `keyname` is what you name this particular key base on where it's going to be used. For example, you may call it `staging`, etc.
109
+
110
+ The following command generates the private key and immediately stores it in the KeyChain access under the name provided:
111
+
112
+ secrets -g -x staging
113
+
114
+ Now, whenever you need to encrypt something, in addition to the `-k` and `-K` you can also choose `-x staging`. This will retrieve the key from the KeyChain access, and use it for encryption/decryption.
115
+
116
+ Finally, you can delete a key from KeyChain access by running:
117
+
118
+ secrets -X staging
119
+
120
+ #### KeyChain Key Management
121
+
122
+ Another tiny executable supplied with this library is called `keychain`
123
+
124
+ ```bash
125
+ Usage: keychain item [ add <contents> | find | delete ]
126
+ ```
127
+ You can use this to add an existing key that can be used with the `secrets` later. Of course you can also use the tool to find or delete it.b
128
+
129
+ 3. passing the `-x [keychain access entry name]` flag
130
+
131
+ #### Encryption and Decryption
132
+
133
+ This may be a good time to take a look at the full help message for the `secrets` tool:
134
+
135
+ ```bash
136
+ ❯ exe/secrets -h
137
+ Usage:
138
+ secrets [options]
139
+ Modes:
140
+ -t, --edit decrypt, open encr. file in vim
141
+ -e, --encrypt encrypt mode
142
+ -d, --decrypt decrypt mode
143
+ Private Key:
144
+ -g, --generate generate a new private key
145
+ -p, --password encrypt the key with a password
146
+ -c, --copy copy the new key to a clipboard
147
+ -k, --private-key [key] private key as a string
148
+ -K, --key-file [key-file] file containing the key
149
+ -x, --keychain [key-name] name of the generic password entry
150
+ -X, --delete-key [key-name] delete keychain entry with that name
151
+ Data:
152
+ -s, --string [string] specify a string to encrypt/decrypt
153
+ -f, --file [file] filename to read from
154
+ -o, --output [file] filename to write to
155
+ Data:
156
+ -i, --interactive ask for a key interactively
157
+ -b, --backup create a backup file in the edit mode
158
+ Flags:
159
+ -v, --verbose show additional information
160
+ -T, --trace print a backtrace of any errors
161
+ -E, --examples show several examples
162
+ -V, --version print library version
163
+ -N, --no-color disable color output
164
+ -h, --help show help
165
+ ```
166
+
167
+ ### CLI Usage Examples
168
+
169
+ __Generating the Key__:
170
+
171
+ Generate a new private key into an environment variable:
172
+
173
+ export KEY=$(secrets -g)
174
+ echo $KEY
175
+ # => 75ngenJpB6zL47/8Wo7Ne6JN1pnOsqNEcIqblItpfg4=
176
+
177
+ Generate a new password-protected key, copy to the clipboard & save to a file:
178
+
179
+ secrets -gpc -o ~/.key
180
+ New Password : ••••••••••
181
+ Confirm Password : ••••••••••
182
+
183
+ Encrypt a plain text string with a key, and save the output to a file:
184
+
185
+ secrets -e -s "secret string" -k $KEY -o file.enc
186
+ cat file.enc
187
+ # => Y09MNDUyczU1S0UvelgrLzV0RTYxZz09CkBDMEw4Q0R0TmpnTm9md1QwNUNy%T013PT0K
188
+
189
+ Decrypt a previously encrypted string:
190
+
191
+ secrets -d -s $(cat file.enc) -k $KEY
192
+ # => secret string
193
+
194
+ Encrypt a file and save it to secrets.enc:
195
+
196
+ secrets -e -f app-secrets.yml -o app-secrets.enc -k $KEY
197
+
198
+ Decrypt an encrypted file and print it to STDOUT:
199
+
200
+ secrets -df app-secrets.enc -k $KEY
201
+
202
+ ##### Inline Editing
203
+
204
+ The `secrets` CLI tool supports one interesting mode where you can open an encrypted file in an `$EDITOR`, and edit it's unencrypted version (stored temporarily in a temp file), and upon saving and exiting the gem will automatically diff the new and old content, and if different – will save encrypt it and overwrite the original file.
205
+
206
+ In this mode several flags are of importance:
207
+
208
+ -b (--backup) – will create a backup of the original file
209
+ -v (--verbose) - will show additional info about file sizes
210
+
211
+ Here is a full command that opens a file specified by `-f | --file`, using the key specified in `-K | --key-file`, in the editor defined by the `$EDITOR` environment variable (or if not set – defaults to `/bin/vi`)".
212
+
213
+ NOTE: while much effort has been made to ensure that the gem is bug free, the reality is that no software is bug free. Please make sure to backup your encrypted file before doing it for the first few times to get familiar with the command.
214
+
215
+ To edit an encrypted file in $EDITOR, while asking for a key (`-i | --interactive`), creating a backup file (`-b | --backup`):
216
+
217
+ secrets -tibf data.enc
218
+ # => Private Key: ••••••••••••••••••••••••••••••••••••••••••••
219
+ #
220
+ # => Diff:
221
+ # 3c3
222
+ # # (c) 2015 Konstantin Gredeskoul. All rights reserved.
223
+ # ---
224
+ # # (c) 2016 Konstantin Gredeskoul. All rights reserved.
225
+
226
+ ### Ruby API
227
+
228
+ To use this library you must include the main `Secrets` module into your library.
229
+
230
+ Any class including `Secrets` will be decorated with new class methods `#private_key` and `#create_private_key`, as well as instance methods `#encr`, and `#decr`.
231
+
232
+ `#create_private_key` will generate a new key each time it's called, while `#private_key` 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 `Secrets` will use it's own key (unless the key is assigned).
233
+
234
+ The following example illustrates this point:
235
+
236
+ ```ruby
237
+ require 'secrets'
238
+
239
+ class TestClass
240
+ include Secrets
241
+ end
242
+ @key = TestClass.create_private_key
243
+ @key.eql?(TestClass.private_key) # => false
244
+ # A new key was created and saved in #private_key accessor.
245
+
246
+ class SomeClass
247
+ include Secrets
248
+ private_key TestClass.private_key
249
+ end
250
+
251
+ @key.eql?(SomeClass.private_key) # => true (it was assigned)
252
+ ```
253
+
254
+ #### Encryption and Decryption
255
+
256
+ So how would we use this library from another ruby project to encrypt and decrypt values?
257
+
258
+ After including the `Secrets` module in a ruby class, the class will now have the `#encr` and `#decr` instance methods, as well as `#secret` and `#create_private_key class methods.
259
+
260
+ Therefore you could write something like this below, protecting a sensitive string using a class-level secret.
261
+
262
+ ```ruby
263
+ require 'secrets'
264
+ class TestClass
265
+ include Secrets
266
+ private_key ENV['SECRET']
267
+
268
+ def sensitive_value=(value)
269
+ @sensitive_value = encr(value, self.class.private_key)
270
+ end
271
+ def sensitive_value
272
+ decr(@sensitive_value, self.class.private_key)
273
+ end
274
+ end
275
+ ```
276
+
277
+ ### Configuration
278
+
279
+ The library offers a typical `Secrets::Configuration` class which can be used to tweak some of the internals of the gem. This is really meant for a very advanced user who knows what she is doing. The following snippet is actually part of the Configuration class itself, but can be overridden by your code that uses and initializes this library. `Configuration` is a singleton, so changes to it will propagate to any subsequent calls to the gem.
280
+
281
+ ```ruby
282
+ Secrets::Configuration.configure do |config|
283
+ config.password_cipher = 'AES-128-CBC' #
284
+ config.data_cipher = 'AES-256-CBC'
285
+ config.private_key_cipher = config.data_cipher
286
+ config.compression_enabled = true
287
+ config.compression_level = Zlib::BEST_COMPRESSION
288
+ end
289
+ ```
290
+
291
+ As you can see, it's possible to change the default cipher typem, although not all ciphers will be code-compatible with the current algorithm, and may require additional code changes.
292
+
293
+ ## Managing Keys
294
+
295
+ There is a separate discussion about ways to securely store private keys in [MANAGING-KEYS.md](https://github.com/kigster/secrets-cipher-base64/blob/master/MANAGING-KEYS.md).
296
+
297
+ ## Development
298
+
299
+ 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.
300
+
301
+ To install this gem onto your local machine, run `bundle exec rake install`. 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).
302
+
303
+ ## Contributing
304
+
305
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/secrets-cipher-base64.
306
+
307
+ ## License
308
+
309
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
310
+
311
+ ## Author
312
+
313
+ This library is the work of [Konstantin Gredeskoul](http:/kig.re), &copy; 2016, distributed under the MIT license.
314
+
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ #require 'guard/notifiers/terminal_notifier'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require 'yard'
7
+ YARD::Rake::YardocTask.new do |t|
8
+ t.files = %w(lib/**/*.rb exe/*.rb - README.md MANAGING-KEYS.md LICENSE)
9
+ t.options.unshift('--title', '"Secrets – Symmetric Key Encryption for Your Data"')
10
+ system('open doc/index.html')
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "secrets"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start