shhh 1.5.4 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +127 -87
- data/exe/shhh +2 -2
- data/lib/shhh/app/args.rb +29 -12
- data/lib/shhh/app/cli.rb +71 -110
- data/lib/shhh/app/commands/command.rb +10 -7
- data/lib/shhh/app/commands/delete_keychain_item.rb +1 -1
- data/lib/shhh/app/commands/encrypt_decrypt.rb +2 -2
- data/lib/shhh/app/commands/generate_key.rb +3 -3
- data/lib/shhh/app/commands/open_editor.rb +3 -3
- data/lib/shhh/app/commands/print_key.rb +2 -5
- data/lib/shhh/app/commands/show_examples.rb +1 -1
- data/lib/shhh/app/commands/show_help.rb +2 -2
- data/lib/shhh/app/commands/show_language_examples.rb +1 -1
- data/lib/shhh/app/commands/show_version.rb +1 -1
- data/lib/shhh/app/commands.rb +1 -1
- data/lib/shhh/app/input/handler.rb +6 -5
- data/lib/shhh/app/keychain.rb +2 -2
- data/lib/shhh/app/nlp/translator.rb +1 -1
- data/lib/shhh/app/password/cache/client.rb +46 -0
- data/lib/shhh/app/password/cache/server.rb +33 -0
- data/lib/shhh/app/password/cache.rb +14 -0
- data/lib/shhh/app/private_key/handler.rb +1 -1
- data/lib/shhh/application.rb +85 -0
- data/lib/shhh/configuration.rb +1 -1
- data/lib/shhh/errors.rb +16 -7
- data/lib/shhh/version.rb +1 -1
- data/lib/shhh.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d5c47820b4c177b5647c092f84686ef74b169fa
|
4
|
+
data.tar.gz: 26ae8727ec033817a6b9cb7c9fc834d952138c40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b9fbca8b285a087362d86a87b8f596878956a08c288fa34ebb31cf23dc5ef88c02765bce1a8388a713c437c44c40057dd165de2c61d4acd2006ea49e78ca483
|
7
|
+
data.tar.gz: 11813a61d0d08a6badebd7363188966226f08c77f1f038e2a49ca69a7b1578b87dd5b3ef3accb0479b7c3779284f7c0be280294879478ad858e9831b1daf2915
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
# Shhh — Your Encryption Best Friend
|
2
3
|
|
3
4
|
[![Gem Version](https://badge.fury.io/rb/shhh.svg)](https://badge.fury.io/rb/shhh)
|
@@ -22,8 +23,8 @@ And finally, in addition to the rich CLI interface of the `shhh` executable, the
|
|
22
23
|
|
23
24
|
### How It Works
|
24
25
|
|
25
|
-
1. You start with a piece of sensitive data, say it's called _X_.
|
26
|
-
2. _X_ is currently a file on your file system, unencrypted.
|
26
|
+
1. You start with a piece of sensitive data, say it's called _X_.
|
27
|
+
2. _X_ is currently a file on your file system, unencrypted.
|
27
28
|
2. You use __shhh__ (with `-g` — for "generate") to make a new encryption key. The key is 256 bits, or 32 bytes, or 45 bytes when base64-encoded.
|
28
29
|
3. You must save this key somewhere safe. We'll talk about this further.
|
29
30
|
4. You use __shhh__ (with `-e`) to encrypt _X_ with the key, and save into _Y_.
|
@@ -35,7 +36,7 @@ And finally, in addition to the rich CLI interface of the `shhh` executable, the
|
|
35
36
|
|
36
37
|
The `shhh` executable as well as the Ruby API provide:
|
37
38
|
|
38
|
-
* Symmetric data encryption with:
|
39
|
+
* Symmetric data encryption with:
|
39
40
|
* the cipher `AES-256-CBC` used by the US Government
|
40
41
|
* 256-bit private key
|
41
42
|
* which can be auto-generated, and is a *base64-encoded* string which is 45 characters long. The *decoded* secret is always 32 characters long (or 256 bytes long).
|
@@ -44,23 +45,22 @@ The `shhh` executable as well as the Ruby API provide:
|
|
44
45
|
* Rich command line interface with some innovative features, such as inline editing of an encrypted file, using your favorite `$EDITOR`.
|
45
46
|
* Data handling:
|
46
47
|
* Automatic compression of the data upon encryption
|
47
|
-
* Automatic base64 encryption to make all encrypted strings fit onto a single line.
|
48
|
+
* Automatic base64 encryption to make all encrypted strings fit onto a single line.
|
48
49
|
* This makes the format suitable for YAML or JSON configuration files, where only the values are encrypted.
|
49
|
-
* Rich Ruby API
|
50
|
+
* Rich Ruby API
|
50
51
|
* (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.
|
51
52
|
|
52
53
|
### Symmetric Encryption
|
53
54
|
|
54
|
-
Symmetric encryption simply means that we are using the same private key to encrypt and decrypt.
|
55
|
+
Symmetric encryption simply means that we are using the same private key to encrypt and decrypt.
|
55
56
|
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*).
|
56
57
|
|
57
58
|
## Installation
|
58
59
|
|
59
60
|
If you plan on using the library in your ruby project with Bundler managing its dependencies, just include the following line in your `Gemfile`:
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
```
|
62
|
+
gem 'shhh'
|
63
|
+
|
64
64
|
And then run `bundle`.
|
65
65
|
|
66
66
|
Or install it into the global namespace with `gem install` command:
|
@@ -69,6 +69,12 @@ Or install it into the global namespace with `gem install` command:
|
|
69
69
|
$ shhh -h
|
70
70
|
$ shhh -E # see examples
|
71
71
|
|
72
|
+
### BASH Completion (Optional Step)
|
73
|
+
|
74
|
+
After gem installation, an message will tell you to install a shown BASH script to your `~/.bashrc` or equivalent.
|
75
|
+
|
76
|
+
Should you choose to install it (this part is optional), you will be able to use "tab-tab" after typing `shhh` and you'll be able to choose from all supported flags.
|
77
|
+
|
72
78
|
## Usage
|
73
79
|
|
74
80
|
### Private Keys
|
@@ -76,7 +82,7 @@ Or install it into the global namespace with `gem install` command:
|
|
76
82
|
This library relies on the existance of the 32-byte private key (aka, *a secret*) to perform encryption and decryption.
|
77
83
|
|
78
84
|
The key can be easily:
|
79
|
-
|
85
|
+
|
80
86
|
* generated by this gem and displayed, copied to the clipboard, or saved to the KeyChain
|
81
87
|
* one way or another must be kept very well protected and secure from attackers
|
82
88
|
* can be fetched from the the Keychain in subsequent encryption/decryption steps
|
@@ -90,8 +96,8 @@ Encrypted private key will be considerably longer, perhaps 200-300 characters lo
|
|
90
96
|
When the private key is encrypted, `shhh` will request the password every time it is used. We are looking at adding a caching layer with a configuerable timeout, so that the password is only re-entered once per given period.
|
91
97
|
|
92
98
|
### Command Line (CLI)
|
93
|
-
|
94
|
-
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.
|
99
|
+
|
100
|
+
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.
|
95
101
|
|
96
102
|
#### Generating and Using Private Keys
|
97
103
|
|
@@ -111,36 +117,36 @@ Or create a password-protected key, and save it to a file:
|
|
111
117
|
|
112
118
|
shhh -gcp -o ~/.secret
|
113
119
|
# New Password: ••••••••••
|
114
|
-
# Confirm Password: ••••••••••
|
120
|
+
# Confirm Password: ••••••••••
|
115
121
|
|
116
122
|
You can subsequently use the private key by either:
|
117
123
|
|
118
|
-
1. passing the `-k [key value]` flag
|
119
|
-
2. passing the `-K [key file]` flag3.
|
124
|
+
1. passing the `-k [key value]` flag
|
125
|
+
2. passing the `-K [key file]` flag3.
|
120
126
|
3. pasting or typing the key with the `-i` (interactive) flag
|
121
127
|
4. passing the `-x [keychain access entry name]` flag to read from Mac OS-X KeyChain Access's generic password field.
|
122
128
|
|
123
129
|
#### Using KeyChain Access on Mac OS-X
|
124
130
|
|
125
|
-
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:
|
131
|
+
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:
|
126
132
|
|
127
133
|
* 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.
|
128
134
|
* If you sync your keychain with iCloud you will have access to it on other machines
|
129
135
|
|
130
|
-
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.
|
136
|
+
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.
|
131
137
|
|
132
138
|
The following command generates the private key and immediately stores it in the KeyChain access under the name provided:
|
133
139
|
|
134
140
|
shhh -g -x staging
|
135
141
|
|
136
142
|
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.
|
137
|
-
|
143
|
+
|
138
144
|
Finally, you can delete a key from KeyChain access by running:
|
139
|
-
|
145
|
+
|
140
146
|
shhh --keychain-del staging
|
141
|
-
|
147
|
+
|
142
148
|
#### KeyChain Key Management
|
143
|
-
|
149
|
+
|
144
150
|
Another tiny executable supplied with this library is called `keychain`
|
145
151
|
|
146
152
|
```bash
|
@@ -152,46 +158,56 @@ You can use this to add an existing key that can be used with the `shhh` later.
|
|
152
158
|
|
153
159
|
This may be a good time to take a look at the full help message for the `shhh` tool, shown naturally with a `-h` or `--help` option.
|
154
160
|
|
155
|
-
```
|
156
|
-
|
161
|
+
```
|
162
|
+
Shhh (1.6.1) – encrypt/decrypt data with a private key
|
157
163
|
|
158
164
|
Usage:
|
159
|
-
|
165
|
+
# Generate a new key:
|
166
|
+
shhh -g [ -c ] [ -p ] [ -x keychain ] [ -o keyfile | -q | ]
|
160
167
|
|
168
|
+
# Encrypt/Decrypt
|
169
|
+
shhh [ -d | -e ] [ -f <file> | -s <string> ]
|
170
|
+
[ -k key | -K keyfile | -x keychain | -i ]
|
171
|
+
[ -o <output file> ]
|
172
|
+
|
173
|
+
# Edit an encrypted file in $EDITOR
|
174
|
+
shhh -t -f <file> [ -b ][ -k key | -K keyfile | -x keychain | -i ]
|
175
|
+
|
161
176
|
Modes:
|
162
177
|
-e, --encrypt encrypt mode
|
163
178
|
-d, --decrypt decrypt mode
|
164
|
-
-t, --edit
|
165
|
-
|
179
|
+
-t, --edit edit an encrypted file in an $EDITOR
|
180
|
+
|
166
181
|
Create a private key:
|
167
182
|
-g, --generate generate a new private key
|
168
183
|
-p, --password encrypt the key with a password
|
169
184
|
-c, --copy copy the new key to the clipboard
|
170
|
-
|
185
|
+
-x, --keychain [key-name] add to (or read from) the OS-X Keychain
|
186
|
+
|
171
187
|
Provide a private key:
|
172
188
|
-i, --interactive Paste or type the key interactively
|
173
189
|
-k, --private-key [key] private key as a string
|
174
190
|
-K, --keyfile [key-file] private key from a file
|
175
|
-
|
176
|
-
Use your KeyChain password entry to store a private key:
|
177
|
-
-x, --keychain [key-name] add to, or read the key from Keychain
|
178
|
-
--keychain-del [key-name] delete keychain entry with that name
|
179
|
-
|
191
|
+
|
180
192
|
Data:
|
181
193
|
-s, --string [string] specify a string to encrypt/decrypt
|
182
194
|
-f, --file [file] filename to read from
|
183
195
|
-o, --output [file] filename to write to
|
184
|
-
|
185
|
-
|
196
|
+
|
186
197
|
Flags:
|
198
|
+
--keychain-del [key-name] delete keychain entry with that name
|
199
|
+
-b, --backup create a backup file in the edit mode
|
187
200
|
-v, --verbose show additional information
|
188
|
-
-q, --quiet silence all output
|
189
201
|
-T, --trace print a backtrace of any errors
|
190
|
-
-
|
191
|
-
-L, --language natural language examples
|
202
|
+
-q, --quiet silence all output
|
192
203
|
-V, --version print library version
|
193
204
|
-N, --no-color disable color output
|
205
|
+
|
206
|
+
Help & Examples:
|
207
|
+
-E, --examples show several examples
|
208
|
+
-L, --language natural language examples
|
194
209
|
-h, --help show help
|
210
|
+
|
195
211
|
```
|
196
212
|
|
197
213
|
### CLI Usage Examples
|
@@ -224,7 +240,7 @@ Decrypt a previously encrypted string:
|
|
224
240
|
Encrypt a file and save it to shhh.enc:
|
225
241
|
|
226
242
|
shhh -e -f app-shhh.yml -o app-shhh.enc -k $KEY
|
227
|
-
|
243
|
+
|
228
244
|
Decrypt an encrypted file and print it to STDOUT:
|
229
245
|
|
230
246
|
shhh -df app-shhh.enc -k $KEY
|
@@ -237,11 +253,11 @@ In this mode several flags are of importance:
|
|
237
253
|
|
238
254
|
-b (--backup) – will create a backup of the original file
|
239
255
|
-v (--verbose) - will show additional info about file sizes
|
240
|
-
|
241
|
-
Here is a full command that opens a file specified by `-f | --file`, using the key specified in `-K | --
|
256
|
+
|
257
|
+
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`)".
|
242
258
|
|
243
259
|
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.
|
244
|
-
|
260
|
+
|
245
261
|
To edit an encrypted file in $EDITOR, while asking to paste the key (`-i | --interactive`), while creating a backup file (`-b | --backup`):
|
246
262
|
|
247
263
|
shhh -tibf data.enc
|
@@ -256,76 +272,85 @@ To edit an encrypted file in $EDITOR, while asking to paste the key (`-i | --int
|
|
256
272
|
|
257
273
|
### Natural Language Processing
|
258
274
|
|
259
|
-
When shhh is
|
260
|
-
|
261
|
-
|
262
|
-
* unambiguously map arguments to the regular options (the double-dash version)
|
263
|
-
* words that already match double-dash options are double-dashed
|
264
|
-
* the mapping of words into --options is performed
|
265
|
-
* the result is parsed
|
275
|
+
When shhh is invoked, and the first argument does not begin with a dash,
|
276
|
+
then the the NLP (natural language processing) Translator is invoked.
|
277
|
+
The Translator is based on a very simple algorithm:
|
266
278
|
|
267
|
-
|
279
|
+
* ignore any of the words tagged STRIPPED. These are the ambiguous words, or words with duplicate meaning.
|
280
|
+
* map the remaining arguments to regular double-dashed options using the DICTIONARY
|
281
|
+
* words that are a direct match for a --option are automatically double-dashed
|
282
|
+
* remaining words are left as is (these would be file names, key names, etc).
|
283
|
+
* finally, the resulting "new" command line is parsed with regular options.
|
284
|
+
* When arguments include "verbose", NLP system will print "before" and "after"
|
285
|
+
of the arguments, so that any issues can be debugged and corrected.
|
268
286
|
|
269
|
-
CURRENTLY IGNORED WORDS:
|
287
|
+
#### CURRENTLY IGNORED WORDS:
|
270
288
|
|
271
|
-
and, a, the, it, item, to, key, with, about, for, of, new, make
|
289
|
+
and, a, the, it, item, to, key, with, about, for, of, new, make, store, in, print
|
272
290
|
|
273
|
-
|
291
|
+
#### REGULAR WORD MAPPING
|
274
292
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
293
|
+
```
|
294
|
+
________________________________________________________________________
|
295
|
+
clipboard ───────➤ --copy
|
296
|
+
unlock ───────➤ --decrypt
|
297
|
+
open ───────➤ --edit
|
298
|
+
lock ───────➤ --encrypt
|
299
|
+
───────➤ --backup
|
300
|
+
───────➤ --keychain
|
301
|
+
read ───────➤ --file
|
302
|
+
create ───────➤ --generate
|
303
|
+
ask enter type ───────➤ --interactive
|
304
|
+
from ───────➤ --keyfile
|
305
|
+
save write ───────➤ --output
|
306
|
+
using private ───────➤ --private_key
|
307
|
+
value ───────➤ --string
|
308
|
+
silently quietly silent shhh ───────➤ --quiet
|
309
|
+
secure secured protected ───────➤ --password
|
310
|
+
________________________________________________________________________
|
311
|
+
```
|
290
312
|
|
291
|
-
EXAMPLES
|
313
|
+
#### EXAMPLES
|
292
314
|
|
293
315
|
```bash
|
294
|
-
# generate a new private key and copy to the clipboard
|
295
|
-
shhh
|
316
|
+
# generate a new private key and copy to the clipboard but do not print to terminal
|
317
|
+
shhh create new key to clipboard quietly
|
296
318
|
|
297
319
|
# generate and save to a file a password-protected key, silently
|
298
320
|
shhh create a secure key and save it to "my.key"
|
299
321
|
|
300
322
|
# encrypt a plain text string with a key, and save the output to a file
|
301
|
-
shhh encrypt string "secret string" using $
|
323
|
+
shhh encrypt string "secret string" using $(cat my.key) save to file.enc
|
302
324
|
|
303
325
|
# decrypt a previously encrypted string:
|
304
|
-
shhh decrypt string $ENC using
|
326
|
+
shhh decrypt string $ENC using $(cat my.key)
|
305
327
|
|
306
|
-
# encrypt
|
307
|
-
shhh encrypt
|
328
|
+
# encrypt "file.txt" with key from my.key and save it to file.enc
|
329
|
+
shhh encrypt file file.txt with key from my.key and save it to file.enc
|
308
330
|
|
309
331
|
# decrypt an encrypted file and print it to STDOUT:
|
310
|
-
shhh decrypt file
|
332
|
+
shhh decrypt file file.enc with key from "my.key"
|
311
333
|
|
312
|
-
# edit an encrypted file in $EDITOR, ask for key, create a backup
|
313
|
-
shhh edit file
|
334
|
+
# edit an encrypted file in $EDITOR, ask for key, and create a backup upon save
|
335
|
+
shhh edit file file.enc ask for a key and make a backup
|
314
336
|
|
315
337
|
# generate a new password-encrypted key, save it to your Keychain:
|
316
|
-
shhh
|
338
|
+
shhh create a new protected key store in keychain "my-keychain-key"
|
339
|
+
|
340
|
+
# print the key stored in the keychain item "my-keychain-key"
|
341
|
+
shhh print keychain "my-keychain-key"
|
317
342
|
|
318
343
|
# use the new key to encrypt a file:
|
319
|
-
shhh encrypt with keychain
|
344
|
+
shhh encrypt with keychain "my-keychain-key" file "password.txt" and write to "passwords.enc"
|
320
345
|
```
|
321
346
|
|
322
347
|
### Ruby API
|
323
348
|
|
324
349
|
To use this library you must include the main `Shhh` module into your library.
|
325
350
|
|
326
|
-
Any class including `Shhh` will be decorated with new class methods `#private_key` and `#create_private_key`, as well as instance methods `#encr`, and `#decr`.
|
351
|
+
Any class including `Shhh` will be decorated with new class methods `#private_key` and `#create_private_key`, as well as instance methods `#encr`, and `#decr`.
|
327
352
|
|
328
|
-
`#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 `Shhh` will use it's own key (unless the key is assigned).
|
353
|
+
`#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 `Shhh` will use it's own key (unless the key is assigned).
|
329
354
|
|
330
355
|
The following example illustrates this point:
|
331
356
|
|
@@ -360,7 +385,7 @@ require 'shhh'
|
|
360
385
|
class TestClass
|
361
386
|
include Shhh
|
362
387
|
private_key ENV['SECRET']
|
363
|
-
|
388
|
+
|
364
389
|
def sensitive_value=(value)
|
365
390
|
@sensitive_value = encr(value, self.class.private_key)
|
366
391
|
end
|
@@ -370,6 +395,21 @@ class TestClass
|
|
370
395
|
end
|
371
396
|
```
|
372
397
|
|
398
|
+
#### Full Application API
|
399
|
+
|
400
|
+
Since the command line interface offers more than just encryption/decryption, it is available via `Shhh::Application` class.
|
401
|
+
|
402
|
+
The class is instantiated with a hash that would be otherwise generated by `Slop.parse(argv)` – ie, typical `options`.
|
403
|
+
|
404
|
+
Here is an example:
|
405
|
+
|
406
|
+
```ruby
|
407
|
+
require 'shhh/application'
|
408
|
+
|
409
|
+
key = Shhh::Application.new(generate: true).execute
|
410
|
+
# => returns a new private key
|
411
|
+
```
|
412
|
+
|
373
413
|
### Configuration
|
374
414
|
|
375
415
|
The library offers a typical `Shhh::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.
|
@@ -377,7 +417,7 @@ The library offers a typical `Shhh::Configuration` class which can be used to tw
|
|
377
417
|
```ruby
|
378
418
|
require 'zlib'
|
379
419
|
Shhh::Configuration.configure do |config|
|
380
|
-
config.password_cipher = 'AES-128-CBC' #
|
420
|
+
config.password_cipher = 'AES-128-CBC' #
|
381
421
|
config.data_cipher = 'AES-256-CBC'
|
382
422
|
config.private_key_cipher = config.data_cipher
|
383
423
|
config.compression_enabled = true
|
@@ -402,16 +442,16 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
402
442
|
Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/shhh.
|
403
443
|
|
404
444
|
## Feature Ideas
|
405
|
-
|
445
|
+
|
406
446
|
### Natural Language Based API
|
407
447
|
|
408
448
|
This is the proposed mini-idea/specification for an alternative CLI that is at a feature parity with the standard flag-based CLI.
|
409
449
|
|
410
|
-
shhh generate key to the clipboard and keychain
|
411
|
-
shhh encrypt file 'hello' using $key [to output.enc]
|
450
|
+
shhh generate key to the clipboard and keychain
|
451
|
+
shhh encrypt file 'hello' using $key [to output.enc]
|
412
452
|
shhh edit 'passwords.enc' using $key
|
413
453
|
shhh decrypt /etc/secrets encrypted with $key save to ./secrets
|
414
|
-
shhh encrypt with keychain $item file $input
|
454
|
+
shhh encrypt with keychain $item file $input
|
415
455
|
|
416
456
|
## License
|
417
457
|
|
data/exe/shhh
CHANGED
@@ -8,8 +8,8 @@ require 'shhh'
|
|
8
8
|
#ARGV.any?{ |a| a =~ /^-/ } ?
|
9
9
|
begin
|
10
10
|
ARGV.first =~ /^-/ ?
|
11
|
-
::Shhh::App::CLI.new(ARGV.dup).
|
12
|
-
::Shhh::App::NLP::Translator.new(ARGV.dup).translate.and.
|
11
|
+
::Shhh::App::CLI.new(ARGV.dup).execute :
|
12
|
+
::Shhh::App::NLP::Translator.new(ARGV.dup).translate.and.execute
|
13
13
|
rescue Interrupt => e
|
14
14
|
STDERR.flush
|
15
15
|
STDERR.puts "Interrupt, #{e.message}, exiting."
|
data/lib/shhh/app/args.rb
CHANGED
@@ -1,24 +1,41 @@
|
|
1
1
|
module Shhh
|
2
2
|
module App
|
3
|
-
class Args < Struct.new(:opts, :argv)
|
4
|
-
MODE = %i(encrypt decrypt generate edit keychain)
|
5
|
-
KEY = %i(private_key interactive keyfile keychain)
|
6
|
-
OUTPUT = %i(output quiet)
|
7
3
|
|
8
|
-
|
9
|
-
|
4
|
+
class Args
|
5
|
+
|
6
|
+
OPTIONS_MODE_SELECTED = %i(encrypt decrypt generate edit keychain)
|
7
|
+
OPTIONS_REQUIRE_KEY = %i(encrypt decrypt edit)
|
8
|
+
OPTIONS_SPECIFY_KEY = %i(private_key interactive keyfile keychain)
|
9
|
+
OPTIONS_SPECIFY_OUTPUT = %i(output quiet)
|
10
|
+
|
11
|
+
attr_accessor :opts, :selected_options
|
12
|
+
|
13
|
+
def initialize(opts)
|
14
|
+
self.opts = opts
|
15
|
+
self.selected_options = opts.keys.reject { |k| !opts[k] }
|
16
|
+
end
|
17
|
+
|
18
|
+
# TODO: generate these methods dynamically
|
19
|
+
def do_options_specify_mode?
|
20
|
+
do?(OPTIONS_MODE_SELECTED)
|
21
|
+
end
|
22
|
+
|
23
|
+
def do_options_specify_key?
|
24
|
+
do?(OPTIONS_SPECIFY_KEY)
|
25
|
+
end
|
26
|
+
|
27
|
+
def do_options_require_key?
|
28
|
+
do?(OPTIONS_REQUIRE_KEY)
|
29
|
+
end
|
10
30
|
|
11
31
|
def output_class
|
12
|
-
output_type =
|
32
|
+
output_type = OPTIONS_SPECIFY_OUTPUT.find { |o| opts[o] } # includes nil
|
13
33
|
Shhh::App::Output.outputs[output_type]
|
14
34
|
end
|
15
35
|
|
16
36
|
private
|
17
|
-
def
|
18
|
-
!
|
19
|
-
end
|
20
|
-
def options_for(of)
|
21
|
-
of.map{ |o| opts[o] }.compact
|
37
|
+
def do?(list)
|
38
|
+
!(list & selected_options).empty?
|
22
39
|
end
|
23
40
|
|
24
41
|
end
|
data/lib/shhh/app/cli.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
|
2
|
-
#!/usr/bin/env ruby
|
3
1
|
require 'slop'
|
4
2
|
require 'shhh'
|
5
3
|
require 'colored2'
|
6
4
|
require 'yaml'
|
5
|
+
require 'forwardable'
|
7
6
|
require 'openssl'
|
8
|
-
require 'shhh/
|
7
|
+
require 'shhh/application'
|
9
8
|
require 'shhh/errors'
|
10
9
|
require 'shhh/app/commands'
|
11
10
|
require 'shhh/app/keychain'
|
@@ -53,91 +52,66 @@ module Shhh
|
|
53
52
|
# in a cross-platform way inside the {Shhh::App::Keychain} module.
|
54
53
|
|
55
54
|
class CLI
|
56
|
-
|
57
|
-
|
55
|
+
|
56
|
+
extend Forwardable
|
57
|
+
|
58
|
+
def_delegators :@application, :command
|
59
|
+
|
60
|
+
attr_accessor :opts, :application, :outputs, :output_proc
|
58
61
|
|
59
62
|
def initialize(argv)
|
60
63
|
begin
|
61
|
-
|
64
|
+
argv_copy = argv.dup
|
65
|
+
dict = false
|
66
|
+
if argv_copy.include?('--dictionary')
|
67
|
+
dict = true
|
68
|
+
argv_copy.delete('--dictionary')
|
69
|
+
end
|
70
|
+
self.opts = parse(argv_copy)
|
71
|
+
if dict
|
72
|
+
options = opts.parser.unused_options + opts.parser.used_options
|
73
|
+
puts options.map{|o| o.to_s.gsub(/.*(--[\w-]+).*/, '\1') }.sort.join(' ')
|
74
|
+
exit 0
|
75
|
+
end
|
62
76
|
rescue StandardError => e
|
63
77
|
error exception: e
|
64
78
|
return
|
65
79
|
end
|
66
80
|
|
81
|
+
configure_color(argv)
|
67
82
|
|
68
|
-
self.
|
83
|
+
self.application = ::Shhh::Application.new(opts)
|
69
84
|
|
70
|
-
configure_color(argv)
|
71
85
|
select_output_stream
|
72
|
-
initialize_input_handler
|
73
|
-
initialize_key_handler
|
74
86
|
|
75
|
-
self.action = { opts[:encrypt] => :encr, opts[:decrypt] => :decr }[true]
|
76
87
|
end
|
77
88
|
|
78
|
-
def
|
89
|
+
def execute
|
79
90
|
return Shhh::App.exit_code if Shhh::App.exit_code != 0
|
80
|
-
unless opts[:generate]
|
81
|
-
self.key = PrivateKey::Handler.new(opts,
|
82
|
-
input_handler).key
|
83
|
-
end
|
84
91
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
92
|
+
result = application.execute
|
93
|
+
if result.is_a?(Hash)
|
94
|
+
self.output_proc = ::Shhh::App::Args.new({}).output_class
|
95
|
+
error(result)
|
89
96
|
else
|
90
|
-
|
91
|
-
self.output_proc = Args.new(Hash.new, []).output_class
|
92
|
-
command_not_found_error!
|
97
|
+
self.output_proc.call(result)
|
93
98
|
end
|
94
|
-
|
95
|
-
rescue ::OpenSSL::Cipher::CipherError => e
|
96
|
-
error type: 'Cipher Error',
|
97
|
-
details: e.message,
|
98
|
-
reason: 'Perhaps either the secret is invalid, or encrypted data is corrupt.',
|
99
|
-
exception: e
|
100
|
-
|
101
|
-
rescue Shhh::Errors::InvalidEncodingPrivateKey => e
|
102
|
-
error type: 'Private Key Error',
|
103
|
-
details: 'Private key does not appear to be properly encoded. ',
|
104
|
-
reason: (opts[:password] ? nil : 'Perhaps the key is password-protected?'),
|
105
|
-
exception: e
|
106
|
-
|
107
|
-
rescue Shhh::Errors::InvalidPasswordPrivateKey => e
|
108
|
-
error type: 'Error',
|
109
|
-
details: 'Invalid password, private key can not decrypted.'
|
110
|
-
|
111
|
-
rescue Shhh::Errors::Error => e
|
112
|
-
error type: 'Error',
|
113
|
-
details: e.message,
|
114
|
-
exception: e
|
115
|
-
|
116
|
-
rescue StandardError => e
|
117
|
-
error exception: e
|
118
99
|
end
|
119
100
|
|
101
|
+
private
|
102
|
+
|
120
103
|
def error(hash)
|
121
104
|
Shhh::App.error(hash.merge(config: (opts ? opts.to_hash : {})))
|
122
105
|
end
|
123
106
|
|
124
|
-
def editor
|
125
|
-
ENV['EDITOR'] || '/bin/vi'
|
126
|
-
end
|
127
|
-
|
128
|
-
def command
|
129
|
-
@command_class ||= Shhh::App::Commands.find_command_class(opts)
|
130
|
-
@command ||= @command_class.new(self) if @command_class
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
107
|
def select_output_stream
|
136
|
-
|
137
|
-
raise "Can not determine output class from arguments #{opts.to_hash}" unless
|
138
|
-
out_klass && out_klass.is_a?(Class)
|
108
|
+
output_klass = application.args.output_class
|
139
109
|
|
140
|
-
|
110
|
+
unless output_klass && output_klass.is_a?(Class)
|
111
|
+
raise "Can not determine output class from arguments #{opts.to_hash}"
|
112
|
+
end
|
113
|
+
|
114
|
+
self.output_proc = output_klass.new(self).output_proc
|
141
115
|
end
|
142
116
|
|
143
117
|
def configure_color(argv)
|
@@ -147,77 +121,64 @@ module Shhh
|
|
147
121
|
end
|
148
122
|
end
|
149
123
|
|
150
|
-
def initialize_input_handler(handler = Input::Handler.new)
|
151
|
-
self.input_handler = handler
|
152
|
-
end
|
153
|
-
|
154
|
-
def initialize_key_handler
|
155
|
-
self.key_handler = PrivateKey::Handler.new(self.opts, input_handler)
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
def command_not_found_error!
|
160
|
-
if key
|
161
|
-
h = opts.to_hash
|
162
|
-
supplied_opts = h.keys.select { |k| h[k] }.join(', ')
|
163
|
-
error type: 'Options Error',
|
164
|
-
details: 'Unable to determined what command to run',
|
165
|
-
reason: "You provided the following options: #{supplied_opts.bold.yellow}",
|
166
|
-
comments: opts.to_s
|
167
|
-
else
|
168
|
-
raise Shhh::Errors::NoPrivateKeyFound.new('Private key is required')
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
124
|
def parse(arguments)
|
173
125
|
Slop.parse(arguments) do |o|
|
174
|
-
o.banner =
|
175
|
-
o.separator '
|
126
|
+
o.banner = "Shhh (#{Shhh::VERSION}) – encrypt/decrypt data with a private key\n".bold.white
|
127
|
+
o.separator 'Usage:'.yellow
|
128
|
+
o.separator ' # Generate a new key:'.dark
|
129
|
+
o.separator ' shhh -g '.green.bold +
|
130
|
+
'[ -c ] [ -p ] [ -x keychain ] [ -o keyfile | -q | ] '.green
|
131
|
+
o.separator ''
|
132
|
+
o.separator ' # Encrypt/Decrypt '.dark
|
133
|
+
o.separator ' shhh [ -d | -e ] '.green.bold +
|
134
|
+
'[ -f <file> | -s <string> ] '.green
|
135
|
+
o.separator ' [ -k key | -K keyfile | -x keychain | -i ] '.green
|
136
|
+
o.separator ' [ -o <output file> ] '.green
|
137
|
+
o.separator ' '
|
138
|
+
o.separator ' # Edit an encrypted file in $EDITOR '.dark
|
139
|
+
o.separator ' shhh -t -f <file> [ -b ]'.green.bold +
|
140
|
+
'[ -k key | -K keyfile | -x keychain | -i ] '.green
|
176
141
|
o.separator ' '
|
177
142
|
o.separator 'Modes:'.yellow
|
178
|
-
o.bool '-
|
143
|
+
o.bool '-e', '--encrypt', ' encrypt mode'
|
179
144
|
o.bool '-d', '--decrypt', ' decrypt mode'
|
180
|
-
o.bool '-t', '--edit', ' decrypt, open an encr. file in '
|
145
|
+
o.bool '-t', '--edit', ' decrypt, open an encr. file in an $EDITOR'
|
181
146
|
o.separator ' '
|
182
147
|
o.separator 'Create a private key:'.yellow
|
183
148
|
o.bool '-g', '--generate', ' generate a new private key'
|
184
149
|
o.bool '-p', '--password', ' encrypt the key with a password'
|
185
150
|
o.bool '-c', '--copy', ' copy the new key to the clipboard'
|
151
|
+
if Shhh::App.is_osx?
|
152
|
+
o.string '-x', '--keychain', '[key-name] '.blue + 'add to (or read from) the OS-X Keychain'
|
153
|
+
end
|
186
154
|
o.separator ' '
|
187
155
|
o.separator 'Provide a private key:'.yellow
|
188
156
|
o.bool '-i', '--interactive', ' Paste or type the key interactively'
|
189
157
|
o.string '-k', '--private-key', '[key] '.blue + ' private key as a string'
|
190
158
|
o.string '-K', '--keyfile', '[key-file]'.blue + ' private key from a file'
|
191
|
-
if Shhh::App.is_osx?
|
192
|
-
o.separator ' '
|
193
|
-
o.separator 'Use your KeyChain password entry to store a private key:'.yellow
|
194
|
-
o.string '-x', '--keychain', '[key-name] '.blue + 'add to, or read the key from Keychain'
|
195
|
-
o.string '--keychain-del', '[key-name] '.blue + 'delete keychain entry with that name'
|
196
|
-
end
|
197
159
|
o.separator ' '
|
198
160
|
o.separator 'Data:'.yellow
|
199
161
|
o.string '-s', '--string', '[string]'.blue + ' specify a string to encrypt/decrypt'
|
200
162
|
o.string '-f', '--file', '[file] '.blue + ' filename to read from'
|
201
163
|
o.string '-o', '--output', '[file] '.blue + ' filename to write to'
|
202
|
-
o.bool '-b', '--backup', ' create a backup file in the edit mode'
|
203
164
|
o.separator ' '
|
204
|
-
o.separator 'Flags:'.
|
205
|
-
|
206
|
-
|
207
|
-
o.bool '-T', '--trace', ' print a backtrace of any errors'
|
208
|
-
o.bool '-E', '--examples', ' show several examples'
|
209
|
-
o.bool '-L', '--language', ' natural language examples'
|
210
|
-
o.bool '-V', '--version', ' print library version'
|
211
|
-
o.bool '-N', '--no-color', ' disable color output'
|
212
|
-
o.bool '-e', '--encrypt', ' encrypt mode'
|
213
|
-
o.separator ''
|
214
|
-
o.on '--dictionary' do
|
215
|
-
puts o.to_a.map{ |w| "#{w.flags.reject{|f| f.to_s !~ /--/ }.first.to_s}" }.join(' ')
|
216
|
-
exit 0
|
165
|
+
o.separator 'Flags:'.yellow
|
166
|
+
if Shhh::App.is_osx?
|
167
|
+
o.string '--keychain-del', '[key-name] '.blue + 'delete keychain entry with that name'
|
217
168
|
end
|
169
|
+
o.bool '-b', '--backup', ' create a backup file in the edit mode'
|
170
|
+
o.bool '-v', '--verbose', ' show additional information'
|
171
|
+
o.bool '-T', '--trace', ' print a backtrace of any errors'
|
172
|
+
o.bool '-q', '--quiet', ' silence all output'
|
173
|
+
o.bool '-V', '--version', ' print library version'
|
174
|
+
o.bool '-N', '--no-color', ' disable color output'
|
175
|
+
o.separator ' '
|
176
|
+
o.separator 'Help & Examples:'.yellow
|
177
|
+
o.bool '-E', '--examples', ' show several examples'
|
178
|
+
o.bool '-L', '--language', ' natural language examples'
|
179
|
+
o.bool '-h', '--help', ' show help'
|
180
|
+
|
218
181
|
end
|
219
|
-
rescue StandardError => e
|
220
|
-
raise(e)
|
221
182
|
end
|
222
183
|
end
|
223
184
|
end
|
@@ -42,26 +42,29 @@ module Shhh
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
attr_accessor :
|
45
|
+
attr_accessor :application
|
46
46
|
|
47
|
-
def initialize(
|
48
|
-
self.
|
47
|
+
def initialize(application)
|
48
|
+
self.application = application
|
49
49
|
end
|
50
50
|
|
51
51
|
def opts
|
52
|
-
|
52
|
+
application.opts
|
53
|
+
end
|
54
|
+
def opts_hash
|
55
|
+
application.opts_hash
|
53
56
|
end
|
54
57
|
|
55
58
|
def key
|
56
|
-
@key ||=
|
59
|
+
@key ||= application.key
|
57
60
|
end
|
58
61
|
|
59
|
-
def
|
62
|
+
def execute
|
60
63
|
raise Shhh::Errors::AbstractMethodCalled.new(:run)
|
61
64
|
end
|
62
65
|
|
63
66
|
def to_s
|
64
|
-
"#{self.class.short_name.to_s.bold.yellow}, with options: #{
|
67
|
+
"#{self.class.short_name.to_s.bold.yellow}, with options: #{application.args.argv.join(' ').gsub(/--/, '').bold.green}"
|
65
68
|
end
|
66
69
|
|
67
70
|
end
|
@@ -8,19 +8,19 @@ module Shhh
|
|
8
8
|
|
9
9
|
required_options :generate
|
10
10
|
|
11
|
-
def
|
11
|
+
def execute
|
12
12
|
retries ||= 0
|
13
13
|
new_private_key = self.class.create_private_key
|
14
14
|
|
15
15
|
if opts[:password]
|
16
16
|
new_private_key = encr_password(new_private_key,
|
17
|
-
|
17
|
+
application.input_handler.new_password)
|
18
18
|
end
|
19
19
|
|
20
20
|
clipboard_copy(new_private_key) if opts[:copy]
|
21
21
|
|
22
22
|
if opts[:keychain] && Shhh::App.is_osx?
|
23
|
-
Shhh::App::KeyChain.new(opts[:keychain]).add(new_private_key)
|
23
|
+
Shhh::App::KeyChain.new(opts[:keychain], opts).add(new_private_key)
|
24
24
|
end
|
25
25
|
|
26
26
|
new_private_key
|
@@ -18,7 +18,7 @@ module Shhh
|
|
18
18
|
|
19
19
|
attr_accessor :tempfile
|
20
20
|
|
21
|
-
def
|
21
|
+
def execute
|
22
22
|
begin
|
23
23
|
self.tempfile = ::Tempfile.new(::Base64.urlsafe_encode64(opts[:file]))
|
24
24
|
decrypt_content(self.tempfile)
|
@@ -31,7 +31,7 @@ module Shhh
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def launch_editor
|
34
|
-
system("#{
|
34
|
+
system("#{application.editor} #{tempfile.path}")
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
@@ -72,7 +72,7 @@ module Shhh
|
|
72
72
|
out << "\n\nDiff:\n#{diff}"
|
73
73
|
out
|
74
74
|
else
|
75
|
-
raise Shhh::Errors::EditorExitedAbnormally.new("#{
|
75
|
+
raise Shhh::Errors::EditorExitedAbnormally.new("#{application.editor} exited with #{$<}")
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
@@ -4,10 +4,10 @@ module Shhh
|
|
4
4
|
module Commands
|
5
5
|
class ShowHelp < Command
|
6
6
|
|
7
|
-
required_options :help, ->(opts) { opts.keys.all? { |k| !opts[k] } }
|
7
|
+
required_options :help, ->(opts) { opts.to_hash.keys.all? { |k| !opts[k] } }
|
8
8
|
try_after :generate_key, :open_editor, :encrypt_decrypt
|
9
9
|
|
10
|
-
def
|
10
|
+
def execute
|
11
11
|
opts.to_s(prefix: ' ' * 2)
|
12
12
|
end
|
13
13
|
end
|
data/lib/shhh/app/commands.rb
CHANGED
@@ -44,7 +44,7 @@ module Shhh
|
|
44
44
|
|
45
45
|
def find_command_class(opts)
|
46
46
|
self.sorted_commands.each do |command_class|
|
47
|
-
return command_class if command_class.options_satisfied_by?(opts
|
47
|
+
return command_class if command_class.options_satisfied_by?(opts)
|
48
48
|
end
|
49
49
|
nil
|
50
50
|
end
|
@@ -22,15 +22,16 @@ module Shhh
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def new_password
|
25
|
-
password = prompt('New Password :
|
26
|
-
password_confirm = prompt('Confirm Password : ', :blue)
|
27
|
-
|
28
|
-
raise Shhh::Errors::PasswordsDontMatch.new(
|
29
|
-
'The passwords you entered do not match.') if password != password_confirm
|
25
|
+
password = prompt('New Password : ', :blue)
|
30
26
|
|
31
27
|
raise Shhh::Errors::PasswordTooShort.new(
|
32
28
|
'Minimum length is 7 characters.') if password.length < 7
|
33
29
|
|
30
|
+
password_confirm = prompt('Confirm Password : ', :blue)
|
31
|
+
|
32
|
+
raise Shhh::Errors::PasswordsDontMatch.new(
|
33
|
+
'The passwords you entered do not match.') if password != password_confirm
|
34
|
+
|
34
35
|
password
|
35
36
|
end
|
36
37
|
end
|
data/lib/shhh/app/keychain.rb
CHANGED
@@ -54,10 +54,10 @@ module Shhh
|
|
54
54
|
puts "> #{command.yellow.green}" if opts[:verbose]
|
55
55
|
output = `#{command}`
|
56
56
|
result = $?
|
57
|
-
raise Shhh::Errors::
|
57
|
+
raise Shhh::Errors::KeyChainCommandError.new("Command error: #{result}, command: #{command}") unless result.success?
|
58
58
|
output.chomp
|
59
59
|
rescue Errno::ENOENT => e
|
60
|
-
raise Shhh::Errors::
|
60
|
+
raise Shhh::Errors::KeyChainCommandError.new("Command error: #{e.message}, command: #{command}")
|
61
61
|
end
|
62
62
|
|
63
63
|
def stderr_off
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
module Shhh
|
3
|
+
module App
|
4
|
+
module Password
|
5
|
+
module Cache
|
6
|
+
class Client
|
7
|
+
# The URI to connect to
|
8
|
+
|
9
|
+
attr_accessor :uri, :host, :port
|
10
|
+
attr_accessor :config
|
11
|
+
|
12
|
+
def initialize(host: nil,
|
13
|
+
port: nil,
|
14
|
+
config: {})
|
15
|
+
self.config =config
|
16
|
+
self.host = host
|
17
|
+
self.port = port
|
18
|
+
end
|
19
|
+
|
20
|
+
def uri
|
21
|
+
return uri if uri
|
22
|
+
template = 'druby://<%= host %>:<%= port %>>'
|
23
|
+
renderer = ERB.new template
|
24
|
+
self.uri = renderer.result(binding)
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
raise NoMethodError, 'not implemented'
|
29
|
+
# Start a local DRbServer to handle callbacks.
|
30
|
+
|
31
|
+
# Not necessary for this small example, but will be required
|
32
|
+
# as soon as we pass a non-marshallable object as an argument
|
33
|
+
# to a dRuby call.
|
34
|
+
|
35
|
+
# Note: this must be called at least once per process to take any effect.
|
36
|
+
# This is particularly important if your application forks.
|
37
|
+
DRb.start_service
|
38
|
+
# timeserver = DRbObject.new_with_uri(SERVER_URI)
|
39
|
+
# puts timeserver.get_current_time
|
40
|
+
# sleep 10
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'singleton'
|
3
|
+
module Shhh
|
4
|
+
module App
|
5
|
+
module Password
|
6
|
+
module Cache
|
7
|
+
URI='druby://localhost:8787'
|
8
|
+
|
9
|
+
class Server
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
def lookup(key)
|
13
|
+
raise NoMethodError, 'not implemented'
|
14
|
+
return 'tasty bisquits'
|
15
|
+
end
|
16
|
+
|
17
|
+
FRONT_OBJECT=self.instance
|
18
|
+
|
19
|
+
def boot
|
20
|
+
raise NoMethodError, 'not implemented'
|
21
|
+
# The object that handles requests on the server
|
22
|
+
|
23
|
+
$SAFE = 1 # disable eval() and friends
|
24
|
+
|
25
|
+
DRb.start_service(URI, FRONT_OBJECT)
|
26
|
+
# Wait for the drb server thread to finish before exiting.
|
27
|
+
DRb.thread.join
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'shhh'
|
2
|
+
require 'colored2'
|
3
|
+
module Shhh
|
4
|
+
class Application
|
5
|
+
|
6
|
+
attr_accessor :opts,
|
7
|
+
:opts_hash,
|
8
|
+
:args,
|
9
|
+
:action,
|
10
|
+
:key,
|
11
|
+
:input_handler,
|
12
|
+
:key_handler,
|
13
|
+
:result
|
14
|
+
|
15
|
+
def initialize(opts)
|
16
|
+
self.opts = opts
|
17
|
+
self.opts_hash = opts.to_hash
|
18
|
+
self.args = ::Shhh::App::Args.new(opts_hash)
|
19
|
+
initialize_input_handler
|
20
|
+
initialize_key_handler
|
21
|
+
initialize_action
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize_action
|
25
|
+
self.action = if opts[:encrypt] then
|
26
|
+
:encr
|
27
|
+
elsif opts[:decrypt]
|
28
|
+
:decr
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute
|
33
|
+
if args.do_options_require_key? || args.do_options_specify_key?
|
34
|
+
self.key = Shhh::App::PrivateKey::Handler.new(opts, input_handler).key
|
35
|
+
raise Shhh::Errors::NoPrivateKeyFound.new('Private key is required') unless self.key
|
36
|
+
end
|
37
|
+
|
38
|
+
unless command
|
39
|
+
raise Shhh::Errors::InsufficientOptionsError.new(
|
40
|
+
'Can not determine what to do from the options ' + opts.keys.reject { |k| !opts[k] }.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
self.result = command.execute
|
44
|
+
return result
|
45
|
+
|
46
|
+
rescue ::OpenSSL::Cipher::CipherError => e
|
47
|
+
error type: 'Cipher Error',
|
48
|
+
details: e.message,
|
49
|
+
reason: 'Perhaps either the secret is invalid, or encrypted data is corrupt.',
|
50
|
+
exception: e
|
51
|
+
|
52
|
+
rescue Shhh::Errors::Error => e
|
53
|
+
error type: e.class.name.split(/::/)[-1],
|
54
|
+
details: e.message
|
55
|
+
|
56
|
+
rescue StandardError => e
|
57
|
+
error exception: e
|
58
|
+
end
|
59
|
+
|
60
|
+
def command
|
61
|
+
@command_class ||= Shhh::App::Commands.find_command_class(opts)
|
62
|
+
@command ||= @command_class.new(self) if @command_class
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def error(hash)
|
68
|
+
hash
|
69
|
+
end
|
70
|
+
|
71
|
+
def editor
|
72
|
+
ENV['EDITOR'] || '/bin/vi'
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def initialize_input_handler(handler = ::Shhh::App::Input::Handler.new)
|
77
|
+
self.input_handler = handler
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize_key_handler
|
81
|
+
self.key_handler = ::Shhh::App::PrivateKey::Handler.new(self.opts, input_handler)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/shhh/configuration.rb
CHANGED
data/lib/shhh/errors.rb
CHANGED
@@ -5,15 +5,24 @@ module Shhh
|
|
5
5
|
class Shhh::Errors::Error < StandardError; end
|
6
6
|
|
7
7
|
# No secret has been provided for encryption or decryption
|
8
|
-
class
|
9
|
-
|
10
|
-
class
|
11
|
-
class
|
8
|
+
class InsufficientOptionsError < Shhh::Errors::Error; end
|
9
|
+
|
10
|
+
class PasswordError < Shhh::Errors::Error; end
|
11
|
+
class PasswordsDontMatch < Shhh::Errors::PasswordError; end
|
12
|
+
class PasswordTooShort < Shhh::Errors::PasswordError; end
|
13
|
+
|
12
14
|
class EditorExitedAbnormally < Shhh::Errors::Error; end
|
13
|
-
|
14
|
-
class InvalidPasswordPrivateKey < Shhh::Errors::Error; end
|
15
|
+
|
15
16
|
class FileNotFound < Shhh::Errors::Error; end
|
16
|
-
|
17
|
+
|
18
|
+
class DataEncodingVersionMismatch< Shhh::Errors::Error; end
|
19
|
+
|
20
|
+
class KeyError < Shhh::Errors::Error; end
|
21
|
+
class InvalidEncodingPrivateKey < Shhh::Errors::KeyError; end
|
22
|
+
class InvalidPasswordPrivateKey < Shhh::Errors::KeyError; end
|
23
|
+
class NoPrivateKeyFound < Shhh::Errors::KeyError; end
|
24
|
+
|
25
|
+
class KeyChainCommandError < Shhh::Errors::Error; end
|
17
26
|
|
18
27
|
# Method was called on an abstract class. Override such methods in
|
19
28
|
# subclasses, and use subclasses for instantiation of objects.
|
data/lib/shhh/version.rb
CHANGED
data/lib/shhh.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shhh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: require_dir
|
@@ -218,11 +218,15 @@ files:
|
|
218
218
|
- lib/shhh/app/output/file.rb
|
219
219
|
- lib/shhh/app/output/noop.rb
|
220
220
|
- lib/shhh/app/output/stdout.rb
|
221
|
+
- lib/shhh/app/password/cache.rb
|
222
|
+
- lib/shhh/app/password/cache/client.rb
|
223
|
+
- lib/shhh/app/password/cache/server.rb
|
221
224
|
- lib/shhh/app/private_key/base64_decoder.rb
|
222
225
|
- lib/shhh/app/private_key/decryptor.rb
|
223
226
|
- lib/shhh/app/private_key/detector.rb
|
224
227
|
- lib/shhh/app/private_key/handler.rb
|
225
228
|
- lib/shhh/app/short_name.rb
|
229
|
+
- lib/shhh/application.rb
|
226
230
|
- lib/shhh/cipher_handler.rb
|
227
231
|
- lib/shhh/configuration.rb
|
228
232
|
- lib/shhh/data.rb
|