sym 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|