sym 2.1.2 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/README.md +83 -140
- data/bin/sym.completion +5 -4
- data/lib/sym.rb +24 -1
- data/lib/sym/app/cli.rb +22 -85
- data/lib/sym/app/cli_slop.rb +77 -0
- data/lib/sym/app/commands/show_help.rb +0 -1
- data/lib/sym/app/keychain.rb +2 -2
- data/lib/sym/app/password/cache.rb +57 -34
- data/lib/sym/app/password/providers.rb +52 -0
- data/lib/sym/app/password/providers/drb_provider.rb +35 -0
- data/lib/sym/app/password/providers/memcached_provider.rb +42 -0
- data/lib/sym/application.rb +4 -3
- data/lib/sym/configuration.rb +4 -0
- data/lib/sym/extensions/with_retry.rb +17 -0
- data/lib/sym/extensions/with_timeout.rb +14 -0
- data/lib/sym/version.rb +1 -1
- data/sym.gemspec +2 -0
- metadata +36 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0d5e823703d09fb437c0b9f8e11b55dd1a0e204
|
4
|
+
data.tar.gz: 42f5145f34d3d0779422e3c2511d35580d85c033
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b007deff2a49f8a31d451fd433eebc7cca83e8ff28a733b8d37a2b34ca5288460e93aa3e8b078442e6c680296fc19b1152f5deac81c2775acc57f79710478b1
|
7
|
+
data.tar.gz: 1c89daa41bbf54b754e203a65720f452e96546e79825924f8d670f11ef392e8c04ca34a85a706b3aba4c6f081870f08189239b3a5fdf7c2a473fec1e51ca47bc
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -13,97 +13,6 @@
|
|
13
13
|
|
14
14
|
> __sym__ is a command line utility and a Ruby API that makes it _trivial to encrypt and decrypt sensitive data_. Unlike many other existing encryption tools, __sym__ focuses on usability and streamlined interface (CLI), with the goal of making encryption easy and transparent. The result? There is no excuse for keeping your application secrets unencrypted :)
|
15
15
|
|
16
|
-
<hr />
|
17
|
-
## Table of Contents
|
18
|
-
|
19
|
-
<ul class="small site-footer-links">
|
20
|
-
<li>
|
21
|
-
<a href="#description">Description</a>
|
22
|
-
<ul>
|
23
|
-
<li>
|
24
|
-
<a href="#motivation">Motivation</a>
|
25
|
-
</li>
|
26
|
-
<li>
|
27
|
-
<a href="#whats-included">What's Included</a>
|
28
|
-
</li>
|
29
|
-
<li>
|
30
|
-
<a href="#how-it-works">How It Works</a>
|
31
|
-
</li>
|
32
|
-
</ul>
|
33
|
-
</li>
|
34
|
-
<li>
|
35
|
-
<a href="#installation">Installation</a>
|
36
|
-
</li>
|
37
|
-
<li>
|
38
|
-
<a href="#using-sym-with-the-command-line">Using <code>sym</code> with the Command Line</a>
|
39
|
-
<ul>
|
40
|
-
<li>
|
41
|
-
<a href="#private-keys">Private Keys</a>
|
42
|
-
<ul>
|
43
|
-
<li>
|
44
|
-
<a href="#generating-private-keys">Generating Private Keys</a>
|
45
|
-
</li>
|
46
|
-
<li>
|
47
|
-
<a href="#using-keychain-access-on-mac-os-x">Using KeyChain Access on Mac OS-X</a>
|
48
|
-
</li>
|
49
|
-
<li>
|
50
|
-
<a href="#keychain-key-management">KeyChain Key Management</a>
|
51
|
-
</li>
|
52
|
-
<li>
|
53
|
-
<a href="#moving-a-key-to-the-keychain">Moving a Key to the Keychain</a>
|
54
|
-
</li>
|
55
|
-
<li>
|
56
|
-
<a href="#adding-password-to-existing-key">Adding Password to Existing Key</a>
|
57
|
-
</li>
|
58
|
-
<li>
|
59
|
-
<a href="#encryption-and-decryption">Encryption and Decryption</a>
|
60
|
-
</li>
|
61
|
-
</ul>
|
62
|
-
</li>
|
63
|
-
<li>
|
64
|
-
<a href="#cli-usage-examples">CLI Usage Examples</a>
|
65
|
-
<ul>
|
66
|
-
<li>
|
67
|
-
<a href="#inline-editing">Inline Editing</a>
|
68
|
-
</li>
|
69
|
-
</ul>
|
70
|
-
</li>
|
71
|
-
</ul>
|
72
|
-
</li>
|
73
|
-
<li>
|
74
|
-
<a href="#ruby-api">Ruby API</a>
|
75
|
-
<ul>
|
76
|
-
<li>
|
77
|
-
<a href="#encryption-and-decryption-operations">Encryption and Decryption Operations</a>
|
78
|
-
</li>
|
79
|
-
<li>
|
80
|
-
<a href="#full-application-api">Full Application API</a>
|
81
|
-
</li>
|
82
|
-
<li>
|
83
|
-
<a href="#configuration">Configuration</a>
|
84
|
-
</li>
|
85
|
-
</ul>
|
86
|
-
</li>
|
87
|
-
<li>
|
88
|
-
<a href="#encryption-features--cipher-used">Encryption Features & Cipher Used</a>
|
89
|
-
</li>
|
90
|
-
<li>
|
91
|
-
<a href="#development">Development</a>
|
92
|
-
<ul>
|
93
|
-
<li>
|
94
|
-
<a href="#contributing">Contributing</a>
|
95
|
-
</li>
|
96
|
-
</ul>
|
97
|
-
</li>
|
98
|
-
<li>
|
99
|
-
<a href="#license">License</a>
|
100
|
-
</li>
|
101
|
-
<li>
|
102
|
-
<a href="#acknowledgements">Acknowledgements</a>
|
103
|
-
</li>
|
104
|
-
</ul>
|
105
|
-
<hr />
|
106
|
-
|
107
16
|
### Motivation
|
108
17
|
|
109
18
|
The primary goal of this tool is to streamline and simplify handling of relatively sensitive data in the most trasparent and easy to use way as possible, without sacrificing security.
|
@@ -150,18 +59,18 @@ New Password : •••••••••
|
|
150
59
|
Confirm Password : •••••••••
|
151
60
|
BAhTOh1TeW06OkRhdGE6OldyYXBwZXJTdH.....
|
152
61
|
|
153
|
-
❯ sym -ex my-new-key -s 'My secret data' -o secret.enc
|
62
|
+
❯ sym -ex my-new-key -s 'My secret data' -o secret.enc -C
|
154
63
|
Coin::Vault listening at: druby://127.0.0.1:24924
|
155
64
|
Password: •••••••••
|
156
65
|
|
157
66
|
❯ cat secret.enc
|
158
67
|
BAhTOh1TeW06OkRhdGE6OldyYXBFefDFFD.....
|
159
68
|
|
160
|
-
❯ sym -dx my-new-key -f secret.enc
|
69
|
+
❯ sym -dx my-new-key -f secret.enc -C
|
161
70
|
My secret data
|
162
71
|
```
|
163
72
|
|
164
|
-
The line that says `Coin::Vault listening at: druby://127.0.0.1:24924` is the indication that the local dRB server used for caching passwords has been started. Password caching
|
73
|
+
The line that says `Coin::Vault listening at: druby://127.0.0.1:24924` is the indication that the local dRB server used for caching passwords has been started. 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.
|
165
74
|
|
166
75
|
__Direct Editing Encrypted Files__
|
167
76
|
|
@@ -208,14 +117,13 @@ The private key is the cornerstone of the symmetric encryption. Using `sym`, the
|
|
208
117
|
* generated and printed to STDOUT, or saved to Mac OS-X KeyChain or a file
|
209
118
|
* fetched from the Keychain in subsequent operations
|
210
119
|
* password-protected during generation (or import) with the `-p` flag.
|
120
|
+
* password can be cached using either `memcached` or `dRB` server, if the `-C` flag is provided.
|
211
121
|
* must be kept very well protected and secure from attackers.
|
212
122
|
|
213
123
|
The __unencrypted private__ key will be in the form of a base64-encoded string, 45 characters long.
|
214
124
|
|
215
125
|
__Encrypted (with password) private key__ will be considerably longer, perhaps 200-300 characters long.
|
216
126
|
|
217
|
-
When the private key is encrypted, `sym` will request the password only once per 15 minute period. The password is cached using a local dRB server, but this caching can be disabled with `-P` flag.
|
218
|
-
|
219
127
|
#### Generating Private Keys
|
220
128
|
|
221
129
|
Let's generate a new key, and copy it to the clipboard (using `pbcopy` command on Mac OS-X):
|
@@ -289,62 +197,81 @@ You can add a password to a key by combining one of the key description flags (-
|
|
289
197
|
|
290
198
|
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."
|
291
199
|
|
200
|
+
#### Password Caching
|
201
|
+
|
202
|
+
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.
|
203
|
+
|
204
|
+
Specifics of configuring both Cache Providers is left to the `Configuration` class, an example of which is shown below in the Ruby API section.
|
205
|
+
|
206
|
+
In order to control password caching, the following flags are available:
|
207
|
+
|
208
|
+
* `-C` turns on caching
|
209
|
+
* `-T seconds` sets the expiration for cached passwords
|
210
|
+
* `-P 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.
|
211
|
+
|
292
212
|
#### Encryption and Decryption
|
293
213
|
|
294
214
|
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.
|
295
215
|
|
296
216
|
```
|
297
|
-
Sym (2.
|
217
|
+
Sym (2.2.0) – encrypt/decrypt data with a private key
|
298
218
|
|
299
219
|
Usage:
|
300
220
|
# Generate a new key:
|
301
|
-
sym -g [ -p ] [ -x keychain
|
302
|
-
|
303
|
-
# Encrypt/Decrypt
|
304
|
-
sym [ -d | -e ] [ -f <file> | -s <string> ]
|
305
|
-
[ -k key | -K keyfile | -x keychain | -i ]
|
306
|
-
[ -o <output file> ]
|
221
|
+
sym -g [ -p ] [ -x keychain | -o keyfile | -q | ]
|
307
222
|
|
308
|
-
#
|
309
|
-
|
223
|
+
# To specify a key for an operation use any one of:
|
224
|
+
<key-spec> = -k key | -K file | -x keychain | -i
|
310
225
|
|
226
|
+
# Encrypt/Decrypt to STDOUT or output file
|
227
|
+
sym -e <key-spec> [-f <file> | -s <string>] [-o <file>]
|
228
|
+
sym -d <key-spec> [-f <file> | -s <string>] [-o <file>]
|
229
|
+
|
230
|
+
# Edit an encrypted file in $EDITOR
|
231
|
+
sym -t <key-spec> -f <file> [ -b ]
|
232
|
+
|
311
233
|
Modes:
|
312
|
-
-e, --encrypt
|
313
|
-
-d, --decrypt
|
314
|
-
-t, --edit
|
315
|
-
|
234
|
+
-e, --encrypt encrypt mode
|
235
|
+
-d, --decrypt decrypt mode
|
236
|
+
-t, --edit edit encrypted file in an $EDITOR
|
237
|
+
|
316
238
|
Create a new private key:
|
317
|
-
-g, --generate
|
318
|
-
-p, --password
|
319
|
-
|
320
|
-
-M, --password-timeout [timeout] when passwords expire (in seconds)
|
321
|
-
-P, --no-password-cache disables caching of key passwords
|
322
|
-
|
239
|
+
-g, --generate generate a new private key
|
240
|
+
-p, --password encrypt the key with a password
|
241
|
+
|
323
242
|
Read existing private key from:
|
324
|
-
-
|
325
|
-
-
|
326
|
-
-
|
327
|
-
|
243
|
+
-k, --private-key [key] private key (or key file)
|
244
|
+
-K, --keyfile [key-file] private key from a file
|
245
|
+
-x, --keychain [key-name] add to (or read from) the OS-X Keychain
|
246
|
+
-i, --interactive Paste or type the key interactively
|
247
|
+
|
248
|
+
Password Cache:
|
249
|
+
-C, --cache-password enable the cache (off by default)
|
250
|
+
-T, --cache-for [seconds] to cache the password for
|
251
|
+
-P, --cache-provider [provider] type of cache, one of:
|
252
|
+
[ memcached, drb ]
|
253
|
+
|
328
254
|
Data to Encrypt/Decrypt:
|
329
|
-
-s, --string
|
330
|
-
-f, --file
|
331
|
-
-o, --output
|
332
|
-
|
255
|
+
-s, --string [string] specify a string to encrypt/decrypt
|
256
|
+
-f, --file [file] filename to read from
|
257
|
+
-o, --output [file] filename to write to
|
258
|
+
|
333
259
|
Flags:
|
334
|
-
-b, --backup
|
335
|
-
-v, --verbose
|
336
|
-
-
|
337
|
-
-D, --debug
|
338
|
-
-q, --quiet
|
339
|
-
-V, --version
|
340
|
-
-N, --no-color
|
341
|
-
|
260
|
+
-b, --backup create a backup file in the edit mode
|
261
|
+
-v, --verbose show additional information
|
262
|
+
-A, --trace print a backtrace of any errors
|
263
|
+
-D, --debug print debugging information
|
264
|
+
-q, --quiet do not print to STDOUT
|
265
|
+
-V, --version print library version
|
266
|
+
-N, --no-color disable color output
|
267
|
+
|
342
268
|
Utility:
|
343
|
-
-a, --bash-completion
|
344
|
-
|
269
|
+
-a, --bash-completion [file] append shell completion to a file
|
270
|
+
|
345
271
|
Help & Examples:
|
346
|
-
-E, --examples
|
347
|
-
-h, --help
|
272
|
+
-E, --examples show several examples
|
273
|
+
-h, --help show help
|
274
|
+
|
348
275
|
```
|
349
276
|
|
350
277
|
### CLI Usage Examples
|
@@ -485,11 +412,27 @@ The library offers a typical `Sym::Configuration` class which can be used to twe
|
|
485
412
|
require 'zlib'
|
486
413
|
require 'sym'
|
487
414
|
Sym::Configuration.configure do |config|
|
488
|
-
config.password_cipher
|
489
|
-
config.
|
490
|
-
config.private_key_cipher = config.data_cipher
|
415
|
+
config.password_cipher = 'AES-128-CBC'
|
416
|
+
config.private_key_cipher = config.data_cipher
|
491
417
|
config.compression_enabled = true
|
492
|
-
config.compression_level
|
418
|
+
config.compression_level = Zlib::BEST_COMPRESSION
|
419
|
+
|
420
|
+
config.password_cache_timeout = 300
|
421
|
+
config.password_cache_arguments = {
|
422
|
+
drb: {
|
423
|
+
opts: {
|
424
|
+
uri: 'druby://127.0.0.1:24924'
|
425
|
+
}
|
426
|
+
},
|
427
|
+
memcached: {
|
428
|
+
args: %w(127.0.0.1:11211),
|
429
|
+
opts: { namespace: 'sym',
|
430
|
+
compress: true,
|
431
|
+
expires_in: config.password_cache_timeout
|
432
|
+
}
|
433
|
+
|
434
|
+
}
|
435
|
+
}
|
493
436
|
end
|
494
437
|
```
|
495
438
|
|
@@ -504,7 +447,7 @@ The `sym` executable as well as the Ruby API provide:
|
|
504
447
|
* 256-bit private key, that
|
505
448
|
* can be generated and is a *base64-encoded* string about 45 characters long. The *decoded* key is always 32 characters (or 256 bytes) long.
|
506
449
|
* can be optionally password-encrypted using the 128-bit key, and then be automatically detected (and password requested) when the key is used
|
507
|
-
* can have its password cached for 15 minutes locally on the machine using
|
450
|
+
* can optionally have its password cached for 15 minutes locally on the machine using `memcached` or using a `dRB` server
|
508
451
|
* Rich command line interface with some innovative features, such as inline editing of an encrypted file, using your favorite `$EDITOR`.
|
509
452
|
* Data handling:
|
510
453
|
* Automatic compression of the data upon encryption
|
data/bin/sym.completion
CHANGED
@@ -16,11 +16,12 @@ _sym() {
|
|
16
16
|
|
17
17
|
#[[ $COMP_CWORD == 1 ]] && SYM_COMP_OPTIONS="${SYM_COMP_OPTIONS} ${SYM_COMMANDS}"
|
18
18
|
if [[ $prev =~ "-f" || $prev =~ "-o" || $prev =~ "-K" || $prev == "--keyfile" ]] ; then
|
19
|
-
SYM_COMP_OPTIONS="$(find . -type f -depth 1 | sed 's
|
20
|
-
elif [[ "${cur}" == '
|
21
|
-
|
19
|
+
SYM_COMP_OPTIONS="$(find . -type f -depth 1 | sed 's#^.\/##g')"
|
20
|
+
elif [[ "${cur}" == '-' || "${cur}" == -* ]] ; then
|
21
|
+
export DICT_SYM_COMP_OPTIONS=${DICT_SYM_COMP_OPTIONS:-$(sym --dictionary | sed -E 's/ /\n/g')}
|
22
|
+
SYM_COMP_OPTIONS=${DICT_SYM_COMP_OPTIONS}
|
22
23
|
else
|
23
|
-
SYM_COMP_OPTIONS
|
24
|
+
SYM_COMP_OPTIONS="$(find . -type f -depth 1 -name "${prev}*" | sed 's#^.\/##g')"
|
24
25
|
fi
|
25
26
|
|
26
27
|
COMPREPLY=( $(compgen -W "${SYM_COMP_OPTIONS}" -- ${cur}) )
|
data/lib/sym.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'colored2'
|
2
2
|
require 'zlib'
|
3
|
-
require '
|
3
|
+
require 'logger'
|
4
4
|
|
5
5
|
require_relative 'sym/configuration'
|
6
6
|
|
@@ -10,8 +10,29 @@ Sym::Configuration.configure do |config|
|
|
10
10
|
config.private_key_cipher = config.data_cipher
|
11
11
|
config.compression_enabled = true
|
12
12
|
config.compression_level = Zlib::BEST_COMPRESSION
|
13
|
+
|
14
|
+
config.password_cache_timeout = 300
|
15
|
+
|
16
|
+
# When nil is selected, providers are auto-detected.
|
17
|
+
config.password_cache_default_provider = nil
|
18
|
+
config.password_cache_arguments = {
|
19
|
+
drb: {
|
20
|
+
opts: {
|
21
|
+
uri: 'druby://127.0.0.1:24924'
|
22
|
+
}
|
23
|
+
},
|
24
|
+
memcached: {
|
25
|
+
args: %w(127.0.0.1:11211),
|
26
|
+
opts: { namespace: 'sym',
|
27
|
+
compress: true,
|
28
|
+
expires_in: config.password_cache_timeout
|
29
|
+
}
|
30
|
+
|
31
|
+
}
|
32
|
+
}
|
13
33
|
end
|
14
34
|
|
35
|
+
|
15
36
|
#
|
16
37
|
# == Using Sym Library
|
17
38
|
#
|
@@ -117,5 +138,7 @@ module Sym
|
|
117
138
|
file: File.expand_path('../../bin/sym.completion', __FILE__),
|
118
139
|
script: "[[ -f '#{COMPLETION_PATH}' ]] && source '#{COMPLETION_PATH}'",
|
119
140
|
}
|
141
|
+
|
142
|
+
LOGGER = Logger.new(nil) # empty logger
|
120
143
|
end
|
121
144
|
|
data/lib/sym/app/cli.rb
CHANGED
@@ -14,6 +14,7 @@ require 'highline'
|
|
14
14
|
require_relative 'output/file'
|
15
15
|
require_relative 'output/file'
|
16
16
|
require_relative 'output/stdout'
|
17
|
+
require_relative 'cli_slop'
|
17
18
|
|
18
19
|
module Sym
|
19
20
|
module App
|
@@ -51,38 +52,33 @@ module Sym
|
|
51
52
|
# in a cross-platform way inside the {Sym::App::Keychain} module.
|
52
53
|
|
53
54
|
class CLI
|
55
|
+
# brings in #parse(Array[String] args)
|
56
|
+
include CLISlop
|
54
57
|
|
55
58
|
extend Forwardable
|
56
|
-
|
57
59
|
def_delegators :@application, :command
|
58
60
|
|
59
61
|
attr_accessor :opts, :application, :outputs, :output_proc
|
60
62
|
|
61
|
-
def initialize(
|
63
|
+
def initialize(argv_original)
|
62
64
|
begin
|
63
|
-
|
64
|
-
dict =
|
65
|
-
|
66
|
-
|
67
|
-
argv_copy.delete('--dictionary')
|
68
|
-
end
|
69
|
-
self.opts = parse(argv_copy)
|
70
|
-
if dict
|
71
|
-
options = opts.parser.unused_options + opts.parser.used_options
|
72
|
-
puts options.map { |o| o.to_s.gsub(/.*(--[\w-]+).*/, '\1') }.sort.join(' ')
|
73
|
-
exit 0
|
74
|
-
end
|
65
|
+
argv = argv_original.dup
|
66
|
+
dict = argv.delete('--dictionary')
|
67
|
+
self.opts = parse(argv)
|
68
|
+
command_dictionary if dict
|
75
69
|
rescue StandardError => e
|
76
70
|
error exception: e
|
77
71
|
return
|
78
72
|
end
|
79
73
|
|
80
|
-
|
74
|
+
command_no_color(argv_original) if opts[:no_color]
|
81
75
|
|
82
76
|
self.application = ::Sym::Application.new(opts)
|
77
|
+
|
83
78
|
select_output_stream
|
84
79
|
end
|
85
80
|
|
81
|
+
|
86
82
|
def execute
|
87
83
|
return Sym::App.exit_code if Sym::App.exit_code != 0
|
88
84
|
|
@@ -97,90 +93,31 @@ module Sym
|
|
97
93
|
|
98
94
|
private
|
99
95
|
|
96
|
+
def command_dictionary
|
97
|
+
options = opts.parser.unused_options + opts.parser.used_options
|
98
|
+
puts options.map(&:to_s).sort.map { |o| "-#{o[1]}" }.join(' ')
|
99
|
+
exit 0
|
100
|
+
end
|
101
|
+
|
100
102
|
def error(hash)
|
101
103
|
Sym::App.error(hash.merge(config: (opts ? opts.to_hash : {})))
|
102
104
|
end
|
103
105
|
|
104
106
|
def select_output_stream
|
105
107
|
output_klass = application.args.output_class
|
106
|
-
|
107
108
|
unless output_klass && output_klass.is_a?(Class)
|
108
109
|
raise "Can not determine output class from arguments #{opts.to_hash}"
|
109
110
|
end
|
110
|
-
|
111
111
|
self.output_proc = output_klass.new(self).output_proc
|
112
112
|
end
|
113
113
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
self.opts = parse(argv.dup)
|
118
|
-
end
|
114
|
+
def command_no_color(argv)
|
115
|
+
Colored2.disable! # reparse options without the colors to create new help msg
|
116
|
+
self.opts = parse(argv.dup)
|
119
117
|
end
|
120
118
|
|
121
|
-
def
|
122
|
-
|
123
|
-
o.banner = "Sym (#{Sym::VERSION}) – encrypt/decrypt data with a private key\n".bold.white
|
124
|
-
o.separator 'Usage:'.yellow
|
125
|
-
o.separator ' # Generate a new key:'.dark
|
126
|
-
o.separator ' sym -g '.green.bold + '[ -p ] [ -x keychain ] [ -o keyfile | -q | ] '.green
|
127
|
-
o.separator ''
|
128
|
-
o.separator ' # Encrypt/Decrypt '.dark
|
129
|
-
o.separator ' sym [ -d | -e ] '.green.bold + '[ -f <file> | -s <string> ] '.green
|
130
|
-
o.separator ' [ -k key | -K keyfile | -x keychain | -i ] '.green
|
131
|
-
o.separator ' [ -o <output file> ] '.green
|
132
|
-
o.separator ' '
|
133
|
-
o.separator ' # Edit an encrypted file in $EDITOR '.dark
|
134
|
-
o.separator ' sym -t -f <file> [ -b ]'.green.bold + '[ -k key | -K keyfile | -x keychain | -i ] '.green
|
135
|
-
|
136
|
-
o.separator ' '
|
137
|
-
o.separator 'Modes:'.yellow
|
138
|
-
|
139
|
-
o.bool '-e', '--encrypt', ' encrypt mode'
|
140
|
-
o.bool '-d', '--decrypt', ' decrypt mode'
|
141
|
-
o.bool '-t', '--edit', ' decrypt, open an encr. file in an $EDITOR'
|
142
|
-
|
143
|
-
o.separator ' '
|
144
|
-
o.separator 'Create a new private key:'.yellow
|
145
|
-
|
146
|
-
o.bool '-g', '--generate', ' generate a new private key'
|
147
|
-
o.bool '-p', '--password', ' encrypt the key with a password'
|
148
|
-
|
149
|
-
if Sym::App.is_osx?
|
150
|
-
o.string '-x', '--keychain', '[key-name] '.blue + 'add to (or read from) the OS-X Keychain'
|
151
|
-
end
|
152
|
-
|
153
|
-
o.integer '-M', '--password-timeout', '[timeout]'.blue + ' when passwords expire (in seconds)'
|
154
|
-
o.bool '-P', '--no-password-cache', ' disables caching of key passwords'
|
155
|
-
|
156
|
-
o.separator ' '
|
157
|
-
o.separator 'Read existing private key from:'.yellow
|
158
|
-
o.bool '-i', '--interactive', ' Paste or type the key interactively'
|
159
|
-
o.string '-k', '--private-key', '[key] '.blue + ' private key as a string'
|
160
|
-
o.string '-K', '--keyfile', '[key-file]'.blue + ' private key from a file'
|
161
|
-
o.separator ' '
|
162
|
-
o.separator 'Data to Encrypt/Decrypt:'.yellow
|
163
|
-
o.string '-s', '--string', '[string]'.blue + ' specify a string to encrypt/decrypt'
|
164
|
-
o.string '-f', '--file', '[file] '.blue + ' filename to read from'
|
165
|
-
o.string '-o', '--output', '[file] '.blue + ' filename to write to'
|
166
|
-
o.separator ' '
|
167
|
-
o.separator 'Flags:'.yellow
|
168
|
-
o.bool '-b', '--backup', ' create a backup file in the edit mode'
|
169
|
-
o.bool '-v', '--verbose', ' show additional information'
|
170
|
-
o.bool '-T', '--trace', ' print a backtrace of any errors'
|
171
|
-
o.bool '-D', '--debug', ' print debugging information'
|
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 'Utility:'.yellow
|
177
|
-
o.string '-a', '--bash-completion', '[file]'.blue + ' append shell completion to a file'
|
178
|
-
o.separator ' '
|
179
|
-
o.separator 'Help & Examples:'.yellow
|
180
|
-
o.bool '-E', '--examples', ' show several examples'
|
181
|
-
o.bool '-h', '--help', ' show help'
|
182
|
-
|
183
|
-
end
|
119
|
+
def key_spec
|
120
|
+
'<key-spec>'.bold.magenta
|
184
121
|
end
|
185
122
|
end
|
186
123
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Sym
|
2
|
+
module App
|
3
|
+
module CLISlop
|
4
|
+
def parse(arguments)
|
5
|
+
Slop.parse(arguments) do |o|
|
6
|
+
|
7
|
+
o.banner = "Sym (#{Sym::VERSION}) – encrypt/decrypt data with a private key\n".bold.white
|
8
|
+
o.separator 'Usage:'.yellow
|
9
|
+
o.separator ' # Generate a new key:'.dark
|
10
|
+
o.separator ' sym -g '.green.bold + '[ -p ] [ -x keychain | -o keyfile | -q | ] '.green
|
11
|
+
o.separator ''
|
12
|
+
o.separator ' # To specify a key for an operation use any one of:'.dark
|
13
|
+
o.separator ' ' + key_spec + ' = -k key | -K file | -x keychain | -i '.green.bold
|
14
|
+
o.separator ''
|
15
|
+
o.separator ' # Encrypt/Decrypt to STDOUT or output file '.dark
|
16
|
+
o.separator ' sym -e '.green.bold + key_spec + ' [-f <file> | -s <string>] [-o <file>] '.green
|
17
|
+
o.separator ' sym -d '.green.bold + key_spec + ' [-f <file> | -s <string>] [-o <file>] '.green
|
18
|
+
o.separator ' '
|
19
|
+
o.separator ' # Edit an encrypted file in $EDITOR '.dark
|
20
|
+
o.separator ' sym -t '.green.bold + key_spec + ' -f <file> [ -b ]'.green.bold
|
21
|
+
|
22
|
+
o.separator ' '
|
23
|
+
o.separator 'Modes:'.yellow
|
24
|
+
o.bool '-e', '--encrypt', ' encrypt mode'
|
25
|
+
o.bool '-d', '--decrypt', ' decrypt mode'
|
26
|
+
o.bool '-t', '--edit', ' edit encrypted file in an $EDITOR'
|
27
|
+
|
28
|
+
o.separator ' '
|
29
|
+
o.separator 'Create a new private key:'.yellow
|
30
|
+
o.bool '-g', '--generate', ' generate a new private key'
|
31
|
+
o.bool '-p', '--password', ' encrypt the key with a password'
|
32
|
+
|
33
|
+
o.separator ' '
|
34
|
+
o.separator 'Read existing private key from:'.yellow
|
35
|
+
o.string '-k', '--private-key', '[key] '.blue + ' private key (or key file)'
|
36
|
+
o.string '-K', '--keyfile', '[key-file]'.blue + ' private key from a file'
|
37
|
+
if Sym::App.is_osx?
|
38
|
+
o.string '-x', '--keychain', '[key-name] '.blue + 'add to (or read from) the OS-X Keychain'
|
39
|
+
end
|
40
|
+
o.bool '-i', '--interactive', ' Paste or type the key interactively'
|
41
|
+
|
42
|
+
o.separator ' '
|
43
|
+
o.separator 'Password Cache:'.yellow
|
44
|
+
o.bool '-C', '--cache-password', ' enable the cache (off by default)'
|
45
|
+
o.integer '-T', '--cache-for', '[seconds]'.blue + ' to cache the password for'
|
46
|
+
o.string '-P', '--cache-provider', '[provider]'.blue + ' type of cache, one of: ' + "\n\t\t\t\t " +
|
47
|
+
"[ #{Sym::App::Password::Providers.registry.keys.map(&:to_s).join(', ').blue.bold} ]"
|
48
|
+
|
49
|
+
o.separator ' '
|
50
|
+
o.separator 'Data to Encrypt/Decrypt:'.yellow
|
51
|
+
o.string '-s', '--string', '[string]'.blue + ' specify a string to encrypt/decrypt'
|
52
|
+
o.string '-f', '--file', '[file] '.blue + ' filename to read from'
|
53
|
+
o.string '-o', '--output', '[file] '.blue + ' filename to write to'
|
54
|
+
|
55
|
+
o.separator ' '
|
56
|
+
o.separator 'Flags:'.yellow
|
57
|
+
o.bool '-b', '--backup', ' create a backup file in the edit mode'
|
58
|
+
o.bool '-v', '--verbose', ' show additional information'
|
59
|
+
o.bool '-A', '--trace', ' print a backtrace of any errors'
|
60
|
+
o.bool '-D', '--debug', ' print debugging information'
|
61
|
+
o.bool '-q', '--quiet', ' do not print to STDOUT'
|
62
|
+
o.bool '-V', '--version', ' print library version'
|
63
|
+
o.bool '-N', '--no-color', ' disable color output'
|
64
|
+
|
65
|
+
o.separator ' '
|
66
|
+
o.separator 'Utility:'.yellow
|
67
|
+
o.string '-a', '--bash-completion', '[file]'.blue + ' append shell completion to a file'
|
68
|
+
|
69
|
+
o.separator ' '
|
70
|
+
o.separator 'Help & Examples:'.yellow
|
71
|
+
o.bool '-E', '--examples', ' show several examples'
|
72
|
+
o.bool '-h', '--help', ' show help'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/sym/app/keychain.rb
CHANGED
@@ -93,7 +93,7 @@ end
|
|
93
93
|
|
94
94
|
|
95
95
|
#
|
96
|
-
# Usage: add-generic-password [-a account] [-s service] [-w password] [options...] [-A
|
96
|
+
# Usage: add-generic-password [-a account] [-s service] [-w password] [options...] [-A|--trace appPath] [keychain]
|
97
97
|
# -a Specify account name (required)
|
98
98
|
# -c Specify item creator (optional four-character code)
|
99
99
|
# -C Specify item type (optional four-character code)
|
@@ -105,7 +105,7 @@ end
|
|
105
105
|
# -p Specify password to be added (legacy option, equivalent to -w)
|
106
106
|
# -w Specify password to be added
|
107
107
|
# -A Allow any application to access this item without warning (insecure, not recommended!)
|
108
|
-
#
|
108
|
+
# --trace Specify an application which may access this item (multiple --trace options are allowed)
|
109
109
|
# -U Update item if it already exists (if omitted, the item cannot already exist)
|
110
110
|
#
|
111
111
|
# Usage: find-generic-password [-a account] [-s service] [options...] [-g] [keychain...]
|
@@ -1,62 +1,85 @@
|
|
1
|
-
require 'coin'
|
2
1
|
require 'digest'
|
3
2
|
require 'singleton'
|
4
3
|
require 'colored2'
|
4
|
+
require 'timeout'
|
5
|
+
require 'sym/extensions/with_retry'
|
6
|
+
require 'sym/extensions/with_timeout'
|
7
|
+
require 'sym/configuration'
|
8
|
+
require 'sym/app/password/providers'
|
5
9
|
|
6
10
|
module Sym
|
7
11
|
module App
|
8
12
|
module Password
|
13
|
+
|
14
|
+
# +Provider+ is the primary implementation of the underlying cache.
|
15
|
+
# It should support the following API:
|
16
|
+
#
|
17
|
+
# def initialize(*args, **opts, &block)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def read(key)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def write(key, value, expire_timeout_seconds)
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# it must be intantiatable via #new
|
9
27
|
class Cache
|
10
|
-
URI = 'druby://127.0.0.1:24924'
|
11
|
-
DEFAULT_TIMEOUT = 300
|
12
28
|
|
13
29
|
include Singleton
|
30
|
+
include Sym::Extensions::WithRetry
|
31
|
+
include Sym::Extensions::WithTimeout
|
14
32
|
|
15
|
-
attr_accessor :provider, :enabled, :timeout
|
16
|
-
|
17
|
-
def configure(provider: Coin, enabled: true, timeout: DEFAULT_TIMEOUT)
|
18
|
-
Coin.uri = URI if provider == Coin
|
19
|
-
|
20
|
-
self.provider = provider
|
21
|
-
self.enabled = enabled
|
22
|
-
self.timeout = timeout
|
33
|
+
attr_accessor :provider, :enabled, :timeout, :verbose
|
23
34
|
|
35
|
+
def configure(**opts)
|
36
|
+
self.enabled = opts[:enabled]
|
37
|
+
self.verbose = opts[:verbose]
|
38
|
+
self.timeout = opts[:timeout] || ::Sym::Configuration.config.password_cache_timeout
|
39
|
+
self.provider = Providers.provider(opts[:provider])
|
40
|
+
self.enabled = false unless self.provider
|
24
41
|
self
|
25
42
|
end
|
26
43
|
|
27
|
-
|
28
|
-
|
29
|
-
def operation
|
30
|
-
retries ||= TRIES
|
31
|
-
yield if self.enabled
|
32
|
-
rescue StandardError => e
|
33
|
-
if retries == TRIES && Coin.remote_uri.nil?
|
34
|
-
Coin.remote_uri = URI if provider == Coin
|
35
|
-
retries -= 1
|
36
|
-
retry
|
37
|
-
end
|
38
|
-
puts 'WARNING: error reading from DRB server: ' + e.message.red
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
def [] (key)
|
44
|
+
def [](key)
|
44
45
|
cache = self
|
45
|
-
operation
|
46
|
-
cache.provider.read(cache.md5(key))
|
47
|
-
end
|
46
|
+
operation { cache.provider.read(cache.md5(key)) }
|
48
47
|
end
|
49
48
|
|
50
49
|
def []=(key, value)
|
51
50
|
cache = self
|
52
|
-
operation
|
53
|
-
cache.provider.write(cache.md5(key), value, cache.timeout)
|
54
|
-
end
|
51
|
+
operation { cache.provider.write(cache.md5(key), value, cache.timeout) }
|
55
52
|
end
|
56
53
|
|
57
54
|
def md5(string)
|
58
55
|
Digest::MD5.base64digest(string)
|
59
56
|
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def operation
|
61
|
+
return nil unless self.enabled
|
62
|
+
with_timeout(1) do
|
63
|
+
with_retry do
|
64
|
+
yield if block_given?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue Timeout::Error => e
|
68
|
+
error(nil, 'Password cache server timed out...')
|
69
|
+
rescue StandardError => e
|
70
|
+
error(e, 'Error connecting to password caching server...')
|
71
|
+
end
|
72
|
+
|
73
|
+
def error(exception = nil, message = nil)
|
74
|
+
if self.verbose
|
75
|
+
print 'WARNING: '
|
76
|
+
print message ? message.yellow : ''
|
77
|
+
print exception ? exception.message.red : ''
|
78
|
+
puts
|
79
|
+
end
|
80
|
+
self.enabled = false
|
81
|
+
nil
|
82
|
+
end
|
60
83
|
end
|
61
84
|
end
|
62
85
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sym
|
2
|
+
module App
|
3
|
+
module Password
|
4
|
+
module Providers
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :registry
|
8
|
+
attr_accessor :providers
|
9
|
+
attr_accessor :detected
|
10
|
+
|
11
|
+
def register(provider_class)
|
12
|
+
self.registry ||= {}
|
13
|
+
registry[short_name(provider_class)] = provider_class
|
14
|
+
self.providers ||= []
|
15
|
+
self.providers << provider_class
|
16
|
+
end
|
17
|
+
|
18
|
+
# Detect first instance that is "alive?" and return it.
|
19
|
+
def detect
|
20
|
+
self.detected ||= self.providers.inject(nil) do |instance, provider_class|
|
21
|
+
instance || (p = provider_class.new; p.alive? ? p : nil)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def provider(p = nil)
|
26
|
+
provider_from_argument(p) || detect
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def short_name(klass)
|
32
|
+
klass.name.gsub(/.*::(\w+)Provider/, '\1').downcase.to_sym
|
33
|
+
end
|
34
|
+
|
35
|
+
def provider_from_argument(p)
|
36
|
+
case p
|
37
|
+
when String, Symbol
|
38
|
+
provider_class_name = "#{p.to_s.capitalize}Provider"
|
39
|
+
Sym::App::Password::Providers.const_defined?(provider_class_name) ?
|
40
|
+
Sym::App::Password::Providers.const_get(provider_class_name).new :
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Order is important — they are tried in this order for auto detect
|
51
|
+
require 'sym/app/password/providers/memcached_provider'
|
52
|
+
require 'sym/app/password/providers/drb_provider'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'coin'
|
2
|
+
require 'sym/app/password/providers'
|
3
|
+
|
4
|
+
module Sym
|
5
|
+
module App
|
6
|
+
module Password
|
7
|
+
module Providers
|
8
|
+
class DrbProvider
|
9
|
+
|
10
|
+
attr_accessor :coin
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
Coin.uri = Sym::Configuration.config.password_cache_arguments[:drb][:opts][:uri]
|
14
|
+
self.coin = Coin
|
15
|
+
end
|
16
|
+
|
17
|
+
def alive?
|
18
|
+
self.read('bogus') rescue nil
|
19
|
+
self.coin.server_running?
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(*args)
|
23
|
+
coin.server.send(:write, *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def read(*args)
|
27
|
+
coin.send(:read, *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register DrbProvider
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'dalli'
|
3
|
+
require 'sym/app/password/cache'
|
4
|
+
|
5
|
+
module Sym
|
6
|
+
module App
|
7
|
+
module Password
|
8
|
+
module Providers
|
9
|
+
class MemcachedProvider
|
10
|
+
attr_accessor :dalli
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
# disable logging
|
14
|
+
Dalli.logger = Sym::LOGGER
|
15
|
+
self.dalli = ::Dalli::Client.new(
|
16
|
+
* Sym::Configuration.config.password_cache_arguments[:memcached][:args],
|
17
|
+
** Sym::Configuration.config.password_cache_arguments[:memcached][:opts]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def alive?
|
22
|
+
dalli.alive!
|
23
|
+
true
|
24
|
+
rescue Dalli::RingError => e
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def read(key)
|
29
|
+
dalli.get(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(key, value, *)
|
33
|
+
dalli.set(key, value)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
register MemcachedProvider
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/sym/application.rb
CHANGED
@@ -103,9 +103,10 @@ module Sym
|
|
103
103
|
|
104
104
|
def initialize_password_cache
|
105
105
|
args = {}
|
106
|
-
args[:
|
107
|
-
args[:
|
108
|
-
args[:
|
106
|
+
args[:timeout] = opts[:cache_for].to_i if opts[:cache_for]
|
107
|
+
args[:enabled] = opts[:cache_password]
|
108
|
+
args[:verbose] = opts[:verbose]
|
109
|
+
args[:provider] = opts[:cache_provider] if opts[:cache_provider]
|
109
110
|
|
110
111
|
self.password_cache = Sym::App::Password::Cache.instance.configure(args)
|
111
112
|
end
|
data/lib/sym/configuration.rb
CHANGED
@@ -33,7 +33,11 @@ module Sym
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
# See file +lib/sym.rb+ where these values are defined.
|
37
|
+
|
36
38
|
attr_accessor :data_cipher, :password_cipher, :private_key_cipher
|
37
39
|
attr_accessor :compression_enabled, :compression_level
|
40
|
+
attr_accessor :password_cache_default_provider, :password_cache_timeout
|
41
|
+
attr_accessor :password_cache_arguments
|
38
42
|
end
|
39
43
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Sym
|
2
|
+
module Extensions
|
3
|
+
module WithRetry
|
4
|
+
|
5
|
+
def with_retry(retries: 3, fail_block: nil, &block)
|
6
|
+
attempts = 0
|
7
|
+
yield if block_given?
|
8
|
+
rescue StandardError => e
|
9
|
+
raise(e) if attempts >= retries
|
10
|
+
fail_block.call if fail_block
|
11
|
+
attempts += 1
|
12
|
+
retry
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/lib/sym/version.rb
CHANGED
data/sym.gemspec
CHANGED
@@ -38,6 +38,7 @@ EOF
|
|
38
38
|
spec.add_dependency 'activesupport'
|
39
39
|
spec.add_dependency 'highline', '~> 1.7'
|
40
40
|
spec.add_dependency 'coin', '~> 0.1.8'
|
41
|
+
spec.add_dependency 'dalli', '~> 2.7'
|
41
42
|
|
42
43
|
spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
|
43
44
|
spec.add_development_dependency 'simplecov'
|
@@ -45,5 +46,6 @@ EOF
|
|
45
46
|
spec.add_development_dependency 'bundler', '~> 1'
|
46
47
|
spec.add_development_dependency 'rake'
|
47
48
|
spec.add_development_dependency 'rspec', '~> 3'
|
49
|
+
spec.add_development_dependency 'rspec-its'
|
48
50
|
spec.add_development_dependency 'yard'
|
49
51
|
end
|
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.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colored2
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.1.8
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: dalli
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.7'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.7'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: codeclimate-test-reporter
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +178,20 @@ dependencies:
|
|
164
178
|
- - "~>"
|
165
179
|
- !ruby/object:Gem::Version
|
166
180
|
version: '3'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec-its
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
167
195
|
- !ruby/object:Gem::Dependency
|
168
196
|
name: yard
|
169
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,6 +245,7 @@ files:
|
|
217
245
|
- lib/sym/app.rb
|
218
246
|
- lib/sym/app/args.rb
|
219
247
|
- lib/sym/app/cli.rb
|
248
|
+
- lib/sym/app/cli_slop.rb
|
220
249
|
- lib/sym/app/commands.rb
|
221
250
|
- lib/sym/app/commands/base_command.rb
|
222
251
|
- lib/sym/app/commands/bash_completion.rb
|
@@ -237,6 +266,9 @@ files:
|
|
237
266
|
- lib/sym/app/output/noop.rb
|
238
267
|
- lib/sym/app/output/stdout.rb
|
239
268
|
- lib/sym/app/password/cache.rb
|
269
|
+
- lib/sym/app/password/providers.rb
|
270
|
+
- lib/sym/app/password/providers/drb_provider.rb
|
271
|
+
- lib/sym/app/password/providers/memcached_provider.rb
|
240
272
|
- lib/sym/app/private_key/base64_decoder.rb
|
241
273
|
- lib/sym/app/private_key/decryptor.rb
|
242
274
|
- lib/sym/app/private_key/detector.rb
|
@@ -253,6 +285,8 @@ files:
|
|
253
285
|
- lib/sym/errors.rb
|
254
286
|
- lib/sym/extensions/class_methods.rb
|
255
287
|
- lib/sym/extensions/instance_methods.rb
|
288
|
+
- lib/sym/extensions/with_retry.rb
|
289
|
+
- lib/sym/extensions/with_timeout.rb
|
256
290
|
- lib/sym/version.rb
|
257
291
|
- sym-3.0-cli.md
|
258
292
|
- sym.gemspec
|