sym 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +30 -31
  3. data/.envrc +7 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +150 -928
  6. data/.travis.yml +16 -26
  7. data/CHANGELOG.md +206 -167
  8. data/Gemfile +1 -0
  9. data/README.adoc +650 -0
  10. data/Rakefile +9 -3
  11. data/bin/{sym.completion → sym.completion.bash} +9 -14
  12. data/bin/sym.symit.bash +781 -0
  13. data/codecov.yml +29 -0
  14. data/design/sym-help.png +0 -0
  15. data/exe/keychain +1 -1
  16. data/exe/sym +5 -2
  17. data/lib/ruby_warnings.rb +7 -0
  18. data/lib/sym.rb +1 -7
  19. data/lib/sym/app.rb +1 -1
  20. data/lib/sym/app/args.rb +3 -2
  21. data/lib/sym/app/cli.rb +1 -2
  22. data/lib/sym/app/cli_slop.rb +1 -1
  23. data/lib/sym/app/commands.rb +1 -1
  24. data/lib/sym/app/commands/base_command.rb +1 -1
  25. data/lib/sym/app/commands/bash_completion.rb +20 -8
  26. data/lib/sym/app/commands/open_editor.rb +1 -1
  27. data/lib/sym/app/commands/password_protect_key.rb +4 -4
  28. data/lib/sym/app/commands/show_examples.rb +1 -1
  29. data/lib/sym/app/input/handler.rb +7 -1
  30. data/lib/sym/app/keychain.rb +15 -9
  31. data/lib/sym/app/output/noop.rb +2 -1
  32. data/lib/sym/app/password/cache.rb +1 -1
  33. data/lib/sym/app/password/providers.rb +2 -3
  34. data/lib/sym/app/private_key/decryptor.rb +2 -2
  35. data/lib/sym/app/private_key/detector.rb +4 -7
  36. data/lib/sym/application.rb +6 -11
  37. data/lib/sym/constants.rb +28 -13
  38. data/lib/sym/data/wrapper_struct.rb +20 -12
  39. data/lib/sym/errors.rb +11 -2
  40. data/lib/sym/extensions/instance_methods.rb +7 -8
  41. data/lib/sym/extensions/stdlib.rb +0 -1
  42. data/lib/sym/extensions/with_retry.rb +1 -1
  43. data/lib/sym/extensions/with_timeout.rb +1 -1
  44. data/lib/sym/version.rb +30 -5
  45. data/sym.gemspec +35 -35
  46. metadata +88 -71
  47. data/.codeclimate.yml +0 -30
  48. data/README.md +0 -623
  49. data/bin/sym.symit +0 -565
  50. data/lib/sym/app/password/providers/drb_provider.rb +0 -41
data/Rakefile CHANGED
@@ -1,7 +1,8 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
3
4
  require 'yard'
4
-
5
+ require 'timeout'
5
6
 
6
7
  def shell(*args)
7
8
  puts "running: #{args.join(' ')}"
@@ -25,12 +26,17 @@ task :build => :permissions
25
26
 
26
27
  YARD::Rake::YardocTask.new(:doc) do |t|
27
28
  t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE)
28
- t.options.unshift('--title','"Sym – Symmetric Key Encryption for Your Data"')
29
- t.after = ->() { exec('open doc/index.html') }
29
+ t.options.unshift('--title', '"Sym – Symmetric Key Encryption for Your Data"')
30
+ t.after = -> { exec('open doc/index.html') }
30
31
  end
31
32
 
32
33
  RSpec::Core::RakeTask.new(:spec)
33
34
 
35
+ RuboCop::RakeTask.new
36
+
34
37
  task :default => :spec
35
38
 
36
39
 
40
+
41
+
42
+
@@ -11,24 +11,19 @@
11
11
  ( [[ -n $ZSH_EVAL_CONTEXT && $ZSH_EVAL_CONTEXT =~ :file$ ]] || \
12
12
  [[ -n $BASH_VERSION && $0 != "$BASH_SOURCE" ]]) && _s_=1 || _s_=0
13
13
 
14
- bash_version=$(/usr/bin/env bash --version | awk '{FS="version"}{print $4}')
14
+ bash_version=$(bash --version | awk '{FS="version"}{print $4}')
15
15
  bash_version=${bash_version:0:1}
16
16
 
17
- if [[ "${bash_version}" -lt 4 ]]; then
18
- echo "Sym BASH helpers are incompatible with BASH version 3 or older."
19
- echo "Please upgrade your BASH to version 4+ released in 2009. Srsly."
20
- (( $_s_ )) && return 1
21
- (( $_s_ )) || exit 1
22
- fi
23
-
24
- declare -a bash_completion_locations=(/usr/local/etc/bash_completion /usr/etc/bash_completion /etc/bash_completion)
25
- loaded=false
26
- for file in ${bash_completion_locations[@]}; do
27
- [[ -s $file ]] && {
28
- source $file
17
+ [[ -z $(type _filedir 2>/dev/null) ]] && {
18
+ declare -a bash_completion_locations=(/usr/local/etc/bash_completion /usr/etc/bash_completion /etc/bash_completion)
19
+ loaded=false
20
+ for file in ${bash_completion_locations[@]}; do
21
+ [[ -s ${file} ]] && {
22
+ source ${file}
29
23
  break
30
24
  }
31
- done
25
+ done
26
+ }
32
27
 
33
28
  _sym_long_opts() {
34
29
  sym -h | grep -- '--' | egrep '^ -' | awk '{print $2}' | sort
@@ -0,0 +1,781 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # (c) 2017-2018 Konstantin Gredeskoul
4
+ #
5
+ # MIT License, distributed as part of `sym` ruby gem.
6
+ # • https://github.com/kigster/sym
7
+ #
8
+ #==============================================================================
9
+ #
10
+ # The purpose of this script is to transparently edit application secrets in
11
+ # Rails apps or other projects. It simplifies the process of key import, as well
12
+ # as the direct editing, as well as multi-file encryption/decryption routines.
13
+ #
14
+ # The idea is that you set some of the variables below to values specific to your
15
+ # system and working with encrypted files will become very easy.
16
+ #
17
+ # SYMIT__FOLDER is a relative folder to your project root, under which you
18
+ # might keep ALL of your encrypted files. Alternatively, if you keep encrypted
19
+ # files sprinkled around your project, just leave it out, because it defaults
20
+ # to "." — the current folder, and search anything beneath.
21
+ #
22
+ # Variables:
23
+ #
24
+ # # only search ./config folder
25
+ # export SYMIT__FOLDER="config"
26
+ #
27
+ # # this will be the name of your key in OS-X KeyChain
28
+ # export SYMIT__KEY="my-org.engineering.dev" # just a name
29
+ #
30
+ # # This is the extension given to the encrypted files. Ideally, leave it
31
+ # # be as ".enc"
32
+ # export SYMIT__EXTENSION=".enc"
33
+ #
34
+ # And then
35
+ #
36
+ # symit import key [ insecure ] # import a key and password-protect it (or not)
37
+ # symit auto application.yml.enc # auto-decrypts it
38
+ # symit auto application.yml # auto-encrypts it
39
+ # symit decrypt application.yml # finds application.yml.enc and decrypts that.
40
+ #
41
+ #
42
+ # ...and vola! You are editing the encrypted file with sym from the root of
43
+ # your Rails application. Neat, no?
44
+ #
45
+
46
+
47
+ # Check if we are being sourced in, or run as a script:
48
+ ( [[ -n ${ZSH_EVAL_CONTEXT} && ${ZSH_EVAL_CONTEXT} =~ :file$ ]] || \
49
+ [[ -n $BASH_VERSION && $0 != "$BASH_SOURCE" ]]) && _s_=1 || _s_=0
50
+
51
+ (( $_s_ )) && _is_sourced=1
52
+ (( $_s_ )) || _is_sourced=0
53
+
54
+ # Set all the defaults
55
+ function __symit::init() {
56
+ export SYMIT__EXTENSION=${SYMIT__EXTENSION:-'.enc'}
57
+ export SYMIT__FOLDER=${SYMIT__FOLDER:-'.'}
58
+ export SYMIT__KEY=${SYMIT__KEY}
59
+ export SYMIT__MIN_VERSION='latest'
60
+ }
61
+
62
+ # Returns name of the current shell, eg 'bash'
63
+ function __lib::shell::name() {
64
+ echo $(basename $(printf $SHELL))
65
+ }
66
+
67
+ # Returns 'yes' if current shell is BASH
68
+ function __lib::shell::is_bash() {
69
+ [[ $(__lib::shell::name) == "bash" ]] && echo yes
70
+ }
71
+
72
+ # Returns a number representing shell version, eg.
73
+ # 3 or 4 for BASH v3 and v4 respectively.
74
+ function __lib::bash::version_number() {
75
+ echo $BASH_VERSION | awk 'BEGIN{FS="."}{print $1}'
76
+ }
77
+
78
+ # Enable all colors, but only if the STDOUT is a terminal
79
+ function __lib::color::setup() {
80
+ if [[ -t 1 ]]; then
81
+ export txtblk='\e[0;30m' # Black - Regular
82
+ export txtred='\e[0;31m' # Red
83
+ export txtgrn='\e[0;32m' # Green
84
+ export txtylw='\e[0;33m' # Yellow
85
+ export txtblu='\e[0;34m' # Blue
86
+ export txtpur='\e[0;35m' # Purple
87
+ export txtcyn='\e[0;36m' # Cyan
88
+ export txtwht='\e[0;37m' # White
89
+
90
+ export bldblk='\e[1;30m' # Black - Bold
91
+ export bldred='\e[1;31m' # Red
92
+ export bldgrn='\e[1;32m' # Green
93
+ export bldylw='\e[1;33m' # Yellow
94
+ export bldblu='\e[1;34m' # Blue
95
+ export bldpur='\e[1;35m' # Purple
96
+ export bldcyn='\e[1;36m' # Cyan
97
+ export bldwht='\e[1;37m' # White
98
+
99
+ export unkblk='\e[4;30m' # Black - Underline
100
+ export undred='\e[4;31m' # Red
101
+ export undgrn='\e[4;32m' # Green
102
+ export undylw='\e[4;33m' # Yellow
103
+ export undblu='\e[4;34m' # Blue
104
+ export undpur='\e[4;35m' # Purple
105
+ export undcyn='\e[4;36m' # Cyan
106
+ export undwht='\e[4;37m' # White
107
+
108
+ export bakblk='\e[40m' # Black - Background
109
+ export bakred='\e[41m' # Red
110
+ export bakgrn='\e[42m' # Green
111
+ export bakylw='\e[43m' # Yellow
112
+ export bakblu='\e[44m' # Blue
113
+ export bakpur='\e[45m' # Purple
114
+ export bakcyn='\e[46m' # Cyan
115
+ export bakwht='\e[47m' # White
116
+
117
+ export clr='\e[0m' # Text Reset
118
+ export txtrst='\e[0m' # Text Reset
119
+ export rst='\e[0m' # Text Reset
120
+ fi
121
+ }
122
+
123
+ # Unset all the colors, in case we a being piped into
124
+ # something else.
125
+ function __lib::color::reset() {
126
+ export txtblk=
127
+ export txtred=
128
+ export txtgrn=
129
+ export txtylw=
130
+ export txtblu=
131
+ export txtpur=
132
+ export txtcyn=
133
+ export txtwht=
134
+
135
+ export bldblk=
136
+ export bldred=
137
+ export bldgrn=
138
+ export bldylw=
139
+ export bldblu=
140
+ export bldpur=
141
+ export bldcyn=
142
+ export bldwht=
143
+
144
+ export unkblk=
145
+ export undred=
146
+ export undgrn=
147
+ export undylw=
148
+ export undblu=
149
+ export undpur=
150
+ export undcyn=
151
+ export undwht=
152
+
153
+ export bakblk=
154
+ export bakred=
155
+ export bakgrn=
156
+ export bakylw=
157
+ export bakblu=
158
+ export bakpur=
159
+ export bakcyn=
160
+ export bakwht=
161
+
162
+ export clr=
163
+ export txtrst=
164
+ export rst=
165
+ }
166
+
167
+ # Enable or disable the colors based on whether the STDOUT
168
+ # is a proper terminal, or a pipe.
169
+ function __lib::stdout::configure() {
170
+ if [[ -t 1 ]]; then
171
+ __lib::color::setup
172
+ else
173
+ __lib::color::reset
174
+ fi
175
+ }
176
+
177
+ __lib::stdout::configure
178
+
179
+ # Check if we are being run as a script, and if so — bail.
180
+ (( $_s_ )) || {
181
+ printf "${bldred}This script is meant to be sourced into your environment,\n"
182
+ printf "not run on a command line.${clr} \n\n"
183
+
184
+ printf "Please add 'source $0' to your BASH initialization file,\n"
185
+ printf "or run the following command:\n\n"
186
+
187
+ printf " \$ ${bldgrn}sym -B ~/.bash_profile${clr}\n\n"
188
+
189
+ printf "${bldblu}Thanks for using Sym!${clr}\n"
190
+ exit 1
191
+ }
192
+
193
+ # Horizontal line, width of the full terminal
194
+ function __lib::color::hr() {
195
+ local cols=${1:-${COLUMNS}}
196
+ local char=${2:-"—"}
197
+ local color=${3:-${txtylw}}
198
+
199
+ printf "${color}"
200
+ eval "printf \"%0.s${char}\" {1..${cols}}"
201
+ printf "${clr}\n"
202
+ }
203
+
204
+ # Large header, all caps
205
+ function __lib::color::h1() {
206
+ local title=$(echo "$*" | tr 'a-z' 'A-Z')
207
+ len=${#title}
208
+ printf "${bldylw}${title}\n"
209
+ __lib::color::hr ${len} '─'
210
+ }
211
+
212
+ # Smaller header
213
+ function __lib::color::h2() {
214
+ printf "${bldpur}$*${clr}\n"
215
+ }
216
+
217
+ # Shift cursor by N positions to the right
218
+ function __lib::color::cursor-right-by() {
219
+ position=$1
220
+ printf "\e[${position}C"
221
+ }
222
+
223
+ # Shift cursor by N positions to the left
224
+ function __lib::color::cursor-left-by() {
225
+ position=$1
226
+ printf "\e[${position}D"
227
+ }
228
+
229
+ # Shift cursor by N positions up
230
+ function __lib::color::cursor-up-by() {
231
+ position=$1
232
+ printf "\e[${position}A"
233
+ }
234
+
235
+ # Shift cursor by N positions down
236
+ function __lib::color::cursor-down-by() {
237
+ position=$1
238
+ printf "\e[${position}B"
239
+ }
240
+
241
+ # Convert a version string such as "1.50.17" to an integer
242
+ # 101050017 for numeric comparison:
243
+ function __lib::ver-to-i() {
244
+ version=${1}
245
+ echo ${version} | awk 'BEGIN{FS="."}{ printf "1%02d%03.3d%03.3d", $1, $2, $3}'
246
+ }
247
+
248
+ # Convert a result of __lib::ver-to-i() back to a regular version.
249
+ function __lib::i-to-ver() {
250
+ version=${1}
251
+ /usr/bin/env ruby -e "ver='${version}'; printf %Q{%d.%d.%d}, ver[1..2].to_i, ver[3..5].to_i, ver[6..8].to_i"
252
+ }
253
+
254
+ # Prints Usage
255
+ function __symit::usage() {
256
+ echo
257
+ __lib::color::h1 "symit"
258
+
259
+ printf "
260
+ ${bldylw}symit${bldgrn} is a powerful BASH helper, that enhances the CLI encryption
261
+ tool called ${bldred}Sym${clr}, which is a Ruby Gem.
262
+
263
+ Sym has an extensive CLI interface, but it only handles one
264
+ encryption/decryption operation per invocation. With this script, you can
265
+ auto decrypt all files in a given folder, you can import the key in a
266
+ simpler way, and you can save into the environment sym configuration that
267
+ will be used. It also streamlines editing of encrypted files in a given
268
+ folder. Symit can be configured either with the ENV variables, or using
269
+ the CLI flags.\n"
270
+
271
+ printf "
272
+ The recommended way to use ${bldred}symit${clr} is to set the following
273
+ environment variables, which removes the need to pass these values via the
274
+ flags. These variables default to the shown values if not set elsewhere:
275
+
276
+ Perhaps the most critically important variable to set is ${txtylw}SYMIT__KEY${clr}:
277
+ ${txtylw}
278
+ export SYMIT__KEY='my-org.my-app.dev'
279
+ eg: export SYMIT__KEY='github.web.development'
280
+ ${clr}
281
+ The ${txtcya}key${clr} can resolve to a file name, or a name of ENV variable,
282
+ a keychain entry, or be the actual key (not recommended!). See the following
283
+ link for more info:
284
+
285
+ ${undblu}https://github.com/kigster/sym#resolving-the--k-argument${clr}
286
+
287
+ Additional configuration is available through these variables:
288
+ ${txtylw}
289
+ export SYMIT__EXTENSION='${SYMIT__EXTENSION}'
290
+ export SYMIT__FOLDER='${SYMIT__FOLDER}'
291
+ export SYMIT__MIN_VERSION='latest'
292
+ ${clr}
293
+ The last variable defines the minimum Sym version desired. Set it to
294
+ 'latest' to have symit auto-upgrade Sym every time it is invoked.
295
+
296
+ ${clr}\n"
297
+
298
+ __lib::color::h2 "Usage:"
299
+ printf " ${bldgrn}symit [ action ] [ file-path/pattern ] [ flags ]${clr}\n\n"
300
+
301
+ __lib::color::h2 "Actions:"
302
+ printf " Action is the first word that defaults to ${bldylw}edit${clr}.\n\n"
303
+ printf " ${bldcya}Valid actions are below, starting with the Key import or creation:${clr}\n\n"
304
+ printf " ${bldylw}— generate ${clr}create a new secure key, and copies it to the\n"
305
+ printf " clipboard (if supported), otherwise prints to STDOUT\n"
306
+ printf " Key name (set via SYMIT__KEY or -k flag) is required,\n"
307
+ printf " and is used as the KeyChain entry name for the new key.\n\n"
308
+ printf " ${bldylw}— import [insecure]\n"
309
+ printf " ${clr}imports the key from clipboard and adds password\n"
310
+ printf " encryption unless 'insecure' is passed in. Same as above\n"
311
+ printf " in relation with the key parameter.\n\n"
312
+ printf " ${bldcya}The following actions require the file pattern/path argument:${clr}\n"
313
+ printf " ${bldylw}— edit ${clr}Finds all files, and opens them in $EDITOR\n"
314
+ printf " ${bldylw}— encrypt ${clr}Encrypts files matching file-path\n"
315
+ printf " ${bldylw}— decrypt ${clr}Adds the extension to file pattern and decrypts\n"
316
+ printf " ${bldylw}— auto ${clr}encrypts decrypted file, and vice versa\n"
317
+
318
+ echo
319
+ __lib::color::h2 "Flags:"
320
+ printf " -f | --folder DIR ${clr}Top level folder to search.${clr}\n"
321
+ printf " -k | --key KEY ${clr}Key identifier${clr}\n"
322
+ printf " -x | --extension EXT ${clr}Default extension of encrypted files.${clr}\n"
323
+ printf " -n | --dry-run ${clr}Print stuff, but dont do it${clr}\n"
324
+ printf " -a | --all-files ${clr}If provided ALL FILES are operated on${clr}\n"
325
+ printf " ${clr}Use with CAUTION!${clr}\n"
326
+ printf " -v | --verbose ${clr}Print more stuff${clr}\n"
327
+ printf " -q | --quiet ${clr}Print less stuff${clr}\n"
328
+ printf " -h | --help ${clr}Show this help message${clr}\n"
329
+
330
+ echo
331
+ __lib::color::h2 'Encryption key identifier can be:'
332
+ printf "${clr}"
333
+
334
+ printf '
335
+ 1. name of the keychain item storing the keychain (secure)
336
+ 2. name of the environment variable storing the Key (*)
337
+ 3. name of the file storing the key (*)
338
+ 4. the key itself (*)'
339
+
340
+ echo
341
+ printf "${bldred}"
342
+ printf '
343
+ (*) 2-4 are insecure UNLESS the key is encrypted with a password.'; echo
344
+ printf "${clr}\
345
+ Please refer to README about generating password protected keys:\n
346
+ ${bldblu}${undblu}https://github.com/kigster/sym#generating-the-key--examples${clr}\n\n"
347
+ echo
348
+
349
+ __lib::color::h1 'Examples:'
350
+
351
+ printf " To import a key securely, first copy the key to your clipboard,\n"
352
+ printf " and then run the following command, pasting the key when asked:\n\n"
353
+ printf " ❯ ${bldgrn}symit${bldblu} import key ${clr}\n\n"
354
+
355
+ printf " To encrypt or decrypt ALL files in the 'config' directory:${clr}\n\n"
356
+ printf " ❯ ${bldgrn}symit${bldblu} encrypt|decrypt -a -f config ${clr}\n\n"
357
+
358
+ printf " To decrypt all *.yml.enc files in the 'config' directory:${clr}\n\n"
359
+ printf " ❯ ${bldgrn}symit${bldblu} decrypt '*.yml' -f config ${clr}\n\n"
360
+
361
+ printf " To edit an encrypted file ${txtblu}config/application.yml.enc${clr}\n\n"
362
+ printf " ❯ ${bldgrn}symit${bldblu} application.yml${clr}\n\n"
363
+
364
+ printf " To auto decrypt a file ${txtblu}config/settings/crypt/pass.yml.enc${clr}\n\n"
365
+ printf " ❯ ${bldgrn}symit${bldblu} auto config/settings/crypt/pass.yml.enc${clr}\n\n"
366
+
367
+ printf " To automatically decide to either encrypt or decrypt a file,\n"
368
+ printf " based on the file extension use 'auto' command. The first line below\n"
369
+ printf " encrypts the file, second decrypts it, because the file extension is .enc:${clr}\n\n"
370
+
371
+ printf " ❯ ${bldgrn}symit${bldblu} auto config/settings/crypt/pass.yml${clr}\n"
372
+ printf " ❯ ${bldgrn}symit${bldblu} auto config/settings/crypt/pass.yml.enc${clr}\n\n"
373
+
374
+ printf " To encrypt a file ${txtblu}config/settings.yml${clr}\n"
375
+ printf " ❯ ${bldgrn}symit${bldblu} encrypt config/settings.yml${clr}\n\n"
376
+ }
377
+
378
+ function __datum() {
379
+ date +"%m/%d/%Y.%H:%M:%S"
380
+ }
381
+
382
+ function __warn() {
383
+ __lib::color::cursor-left-by 1000
384
+ printf "${bldylw}$* ${bldylw}\n"
385
+ }
386
+ function __err() {
387
+ __lib::color::cursor-left-by 1000
388
+ printf "${bldred}ERROR: ${txtred}$* ${bldylw}\n"
389
+ }
390
+
391
+ function __inf() {
392
+ [[ ${cli__opts__quiet} ]] && return
393
+ __lib::color::cursor-left-by 1000
394
+ printf "${txtblu}$*${clr}\n"
395
+ }
396
+
397
+ function __dbg() {
398
+ [[ ${cli__opts__verbose} ]] || return
399
+ __lib::color::cursor-left-by 1000
400
+ printf "${txtgrn}$*${clr}\n"
401
+ }
402
+
403
+ function __lib::command::print() {
404
+ __inf "${bldylw}❯ ${bldcya}$*${clr}"
405
+ }
406
+
407
+ function __symit::sym::installed_version() {
408
+ __lib::ver-to-i $(gem list | grep sym | awk '{print $2}' | sed 's/(//g;s/)//g')
409
+ }
410
+
411
+ function __symit::sym::latest_version() {
412
+ __lib::ver-to-i $(gem query --remote -n '^sym$' | awk '{print $2}' | sed 's/(//g;s/)//g')
413
+ }
414
+
415
+ function __symit::install::update() {
416
+ local desired_version=$1
417
+ shift
418
+ local current_version=$2
419
+ shift
420
+ local version_args=$*
421
+
422
+ __inf "updating sym to version ${bldylw}$(__lib::i-to-ver ${desired_version})${clr}..."
423
+ printf "${bldblu}" >&1
424
+ echo y | gem uninstall sym --force -x 2>/dev/null
425
+ printf "${clr}" >&1
426
+
427
+ command="gem install sym ${version_args} "
428
+ eval "${command}" >/dev/null
429
+ code=$?
430
+ printf "${clr}" >&2
431
+ if [[ ${code} != 0 ]]; then
432
+ __err "gem install returned ${code}, with command ${bldylw}${command}"
433
+ return 127
434
+ fi
435
+ current_version=$(__symit::sym::installed_version)
436
+ __inf "sym version ${bldylw}$(__lib::i-to-ver ${current_version}) was successfully installed."
437
+ }
438
+
439
+ function __symit::install::gem() {
440
+ if [[ -n ${__symit_last_checked_at} ]]; then
441
+ now=$(date +'%s')
442
+ if [[ $(( $now - ${__symit_last_checked_at} )) -lt 3600 ]]; then
443
+ return
444
+ fi
445
+ fi
446
+
447
+ export __symit_last_checked_at=${now:-$(date +'%s')}
448
+
449
+ __inf "Verifying current sym version, please wait..."
450
+ current_version=$(__symit::sym::installed_version)
451
+ if [[ -n ${SYMIT__MIN_VERSION} ]]; then
452
+ if [[ ${SYMIT__MIN_VERSION} -eq 'latest' ]]; then
453
+ desired_version=$(__symit::sym::latest_version)
454
+ version_args=''
455
+ else
456
+ desired_version=$( __lib::ver-to-i ${SYMIT__MIN_VERSION})
457
+ version_args=" --version ${SYMIT__MIN_VERSION}"
458
+ fi
459
+
460
+ if [[ "${desired_version}" != "${current_version}" ]]; then
461
+ __symit::install::update "${desired_version}" "${current_version}" "${version_args}"
462
+ else
463
+ __inf "${bldgrn}sym${clr} ${txtblu}is on the correct version ${bldylw}$(__lib::i-to-ver ${desired_version})${txtblu} already"
464
+ fi
465
+ else
466
+ if [[ -z ${current_version} ]] ; then
467
+ __dbg "installing latest version of ${bldylw}sym..."
468
+ fi
469
+ fi
470
+ }
471
+
472
+ function __symit::files() {
473
+ eval $(__symit::files::cmd)
474
+ }
475
+
476
+ function __symit::files::cmd() {
477
+ if [[ -n ${cli__opts__file} && -n ${cli__opts__extension} ]]; then
478
+
479
+ local folder=${cli__opts__folder}
480
+ local file="${cli__opts__file}"
481
+ local ext="${cli__opts__extension}"
482
+
483
+ if [[ ${file} =~ '/' ]]; then
484
+ if [[ ${folder} == '.' ]]; then
485
+ folder="$(dirname ${file})"
486
+ else
487
+ folder="${folder}/$(dirname ${file})"
488
+ fi
489
+ file="$(basename ${file})"
490
+ fi
491
+
492
+ if [[ "${cli__opts__action}" == "encrypt" ]] ; then
493
+ printf "find ${folder} -name '${file}' -and -not -name '*${ext}'"
494
+ elif [[ "${cli__opts__action}" == "auto" ]] ; then
495
+ printf "find ${folder} -name '${file}'"
496
+ else # edit, decrypt
497
+ [[ ${file} =~ "${ext}" ]] || file="${file}${ext}"
498
+ printf "find ${folder} -name '${file}'"
499
+ fi
500
+ fi
501
+ }
502
+
503
+ function __symit::command() {
504
+ file=${1}
505
+ if [[ -n "${cli__opts__key}" && -n "${cli__opts__extension}" ]]; then
506
+ action="${cli__opts__action}"
507
+ v="sym__actions__${action}"
508
+ flags="${!v}"
509
+ if [[ ${action} =~ "key" ]]; then
510
+ [[ -n ${cli__opts__verbose} ]] && printf "processing key import action ${bldylw}${action}${clr}\n" >&2
511
+ printf "sym ${flags} ${cli__opts__key} "
512
+ elif [[ ${action} =~ "generate" ]] ; then
513
+ [[ -n ${cli__opts__verbose} ]] && printf "processing generate key action ${bldylw}${action}${clr}\n" >&2
514
+ if [[ -n $(which pbcopy) ]]; then
515
+ out_key=/tmp/outkey
516
+ command="sym ${flags} ${cli__opts__key} -q -o ${out_key}; cat ${out_key} | pbcopy; rm -f ${out_key}"
517
+ printf "${command}"
518
+ else
519
+ printf "sym ${flags} ${cli__opts__key} "
520
+ fi
521
+ elif [[ -n ${file} ]] ; then
522
+ ext="${cli__opts__extension}"
523
+ [[ -z ${ext} ]] && ext='.enc'
524
+ ext=$(echo ${ext} | sed -E 's/[\*\/,.]//g')
525
+ if [[ ${action} =~ "encrypt" ]]; then
526
+ printf "sym ${flags} ${file} -ck ${cli__opts__key} -o ${file}.${ext}"
527
+ elif [[ ${action} =~ "decrypt" ]]; then
528
+ new_name=$(echo ${file} | sed "s/\.${ext}//g")
529
+ [[ "${new_name}" == "${file}" ]] && name="${file}.decrypted"
530
+ printf "sym ${flags} ${file} -ck ${cli__opts__key} -o ${new_name}"
531
+ else
532
+ printf "sym ${flags} ${file} -ck ${cli__opts__key} "
533
+ fi
534
+ else
535
+ printf "printf \"ERROR: not sure how to generate a correct command\\n\""
536
+ fi
537
+ fi
538
+ }
539
+
540
+ function __symit::cleanup() {
541
+ unset sym__actions
542
+ unset cli__opts
543
+ }
544
+
545
+ function __symit::exit() {
546
+ code=${1:-0}
547
+ __symit::cleanup
548
+ echo -n ${code}
549
+ }
550
+
551
+ function __symit::print_cli_args() {
552
+ __dbg "action ${bldylw}: ${cli__opts__action}${clr}"
553
+ __dbg "key ${bldylw}: ${cli__opts__key}${clr}"
554
+ __dbg "file ${bldylw}: ${cli__opts__file}${clr}"
555
+ __dbg "extension ${bldylw}: ${cli__opts__extension}${clr}"
556
+ __dbg "folder ${bldylw}: ${cli__opts__folder}${clr}"
557
+ __dbg "verbose ${bldylw}: ${cli__opts__verbose}${clr}"
558
+ __dbg "dry_run ${bldylw}: ${cli__opts__dry_run}${clr}"
559
+ }
560
+
561
+ function __symit::args::needs_file() {
562
+ if [[ "${cli__opts__action}" == 'edit' || \
563
+ "${cli__opts__action}" == 'auto' || \
564
+ "${cli__opts__action}" == 'encrypt' || \
565
+ "${cli__opts__action}" == 'decrypt' ]]; then
566
+ printf 'yes'
567
+ fi
568
+ }
569
+
570
+ function __symit::validate_args() {
571
+ if [[ -n $(__symit::args::needs_file) && -z ${cli__opts__file} ]]; then
572
+ __err "missing file argument, config/application.yml"
573
+ return $(__symit::exit 2)
574
+ fi
575
+
576
+ if [[ -z "${cli__opts__key}" ]]; then
577
+ __err "Key was not defined, pass it with ${bldblu}-k KEY_ID${bldred}"
578
+ __err "or set it via ${bldgrn}\$SYMIT__KEY${bldred} variable."
579
+ return $(__symit::exit 4)
580
+ fi
581
+
582
+ if [[ -z ${cli__opts__extension} ]]; then
583
+ cli__opts__extension='.enc'
584
+ fi
585
+ }
586
+
587
+ function __symit::run() {
588
+ __symit::cleanup
589
+ __symit::init
590
+
591
+ cli__opts__verbose=''
592
+ cli__opts__quiet=''
593
+ cli__opts__key=${SYMIT__KEY}
594
+ cli__opts__extension=${SYMIT__EXTENSION}
595
+ cli__opts__folder=${SYMIT__FOLDER}
596
+ cli__opts__dry_run=''
597
+ cli__opts__action=edit
598
+ cli__opts__file=''
599
+
600
+ sym__actions__generate=' -cpgx '
601
+ sym__actions__edit=' -t '
602
+ sym__actions__encrypt='-e -f '
603
+ sym__actions__decrypt='-d -f '
604
+ sym__actions__auto=' -n '
605
+ sym__actions__key_secure=' -iqcpx '
606
+ sym__actions__key_insecure=' -iqcx '
607
+ sym__actions__install='install'
608
+
609
+ if [[ -z $1 ]]; then
610
+ __symit::usage
611
+ return $(__symit::exit 0)
612
+ fi
613
+
614
+ while :; do
615
+ case $1 in
616
+ -h|-\?|--help)
617
+ shift
618
+ __symit::usage
619
+ __symit::cleanup
620
+ return $(__symit::exit 0)
621
+ ;;
622
+
623
+ -k|--key)
624
+ shift
625
+ if [[ -z $1 ]]; then
626
+ __err "-k/--key requires an argument" && return $(__symit::exit 1)
627
+ else
628
+ cli__opts__key=$1
629
+ shift
630
+ fi
631
+ ;;
632
+
633
+ -x|--extension)
634
+ shift
635
+ if [[ -z $1 ]]; then
636
+ __err "-x/--extension requires an argument" && return $(__symit::exit 1)
637
+ else
638
+ cli__opts__extension=${1}
639
+ shift
640
+ fi
641
+ ;;
642
+
643
+ -f|--folder)
644
+ shift
645
+ if [[ -z $1 ]]; then
646
+ __err "-f/--folder requires an argument" && return $(__symit::exit 1)
647
+ else
648
+ cli__opts__folder=${1}
649
+ shift
650
+ fi
651
+ ;;
652
+
653
+ -a|--all-files)
654
+ shift
655
+ cli__opts__file="'*'"
656
+ ;;
657
+
658
+ -n|--dry-run)
659
+ shift
660
+ cli__opts__dry_run="yes"
661
+ ;;
662
+
663
+ -v|--verbose)
664
+ shift
665
+ cli__opts__verbose="yes"
666
+ ;;
667
+
668
+ -q|--quiet)
669
+ shift
670
+ cli__opts__quiet="yes"
671
+ ;;
672
+
673
+ import|key)
674
+ shift
675
+ cli__opts__action="key_secure"
676
+ ;;
677
+
678
+ insecure)
679
+ shift
680
+ if [[ "${cli__opts__action}" == 'key_secure' ]] ; then
681
+ cli__opts__action="key_insecure"
682
+ fi
683
+ ;;
684
+
685
+ --) # End of all options.
686
+ shift
687
+ break
688
+ ;;
689
+
690
+ -?*)
691
+ __err 'WARN: Unknown option: %s\n' "$1" >&2
692
+ return $(__symit::exit 127)
693
+ shift
694
+ ;;
695
+
696
+
697
+ ?*)
698
+ param=$1
699
+ v="sym__actions__${param}"
700
+ if [[ ! ${param} =~ '.' && -n "${!v}" ]]; then
701
+ __dbg "Action ${bldylw}${param}${clr} is a valid action."
702
+ cli__opts__action=${param}
703
+ else
704
+ __dbg "Parameter ${bldylw}${param}${clr} is not a valid action,"
705
+ __dbg "therefore it must be a file pattern."
706
+ cli__opts__file=${1}
707
+ fi
708
+ shift
709
+ ;;
710
+
711
+ *) # Default case: If no more options then break out of the loop.
712
+ break
713
+ shift
714
+ esac
715
+ done
716
+
717
+ [[ -n "${cli__opts__verbose}" ]] && __symit::print_cli_args
718
+
719
+ if [[ "${cli__opts__action}" == 'install' ]]; then
720
+ if [[ -n ${cli__opts__dry_run} ]]; then
721
+ __dbg "This command verifies that Sym is properly installed,"
722
+ __dbg "and if not found — installs it."
723
+ return $(__symit::exit 0)
724
+ else
725
+ __symit::install::gem
726
+ return $(__symit::exit 0)
727
+ fi
728
+ fi
729
+
730
+ __symit::validate_args
731
+
732
+ code=$?
733
+ if [[ ${code} != 0 ]]; then
734
+ return $(__symit::exit ${code})
735
+ fi
736
+
737
+ __symit::install::gem
738
+
739
+ changed_count=0
740
+
741
+ if [[ -n "${cli__opts__dry_run}" ]] ; then
742
+ __lib::color::h1 "DRY RUN"
743
+ for file in $(__symit::files); do
744
+ printf " \$ ${bldblu}$(__symit::command ${file})${clr}\n"
745
+ done
746
+ else
747
+ if [[ -n "${cli__opts__file}" ]]; then
748
+ [[ -n ${cli__opts__verbose} ]] && __dbg $(__symit::files)
749
+ declare -a file_list
750
+
751
+ for file in $(__symit::files); do
752
+ local cmd="$(__symit::command ${file})"
753
+ __lib::command::print "${cmd}"
754
+ eval "${cmd}"
755
+ code=$?; [[ ${code} != 0 ]] && __err "command '${bldblu}${cmd}${bldred}' exited with code ${bldylw}${code}"
756
+ changed_count=$(( ${changed_count} + 1))
757
+ done
758
+
759
+ if [[ ${changed_count} == 0 ]]; then
760
+ printf "${undylw}Bad news:${clr}\n\n"
761
+ __warn " No files matched your specification. The following 'find' command"
762
+ __warn " ran to find the file you requested. Please change the name, and "
763
+ __warn " try again.\n"
764
+ __warn " ${bldblu}$(__symit::files::cmd)${clr}\n\n"
765
+ return $(__symit::exit 5)
766
+ fi
767
+
768
+ else # opts[file]
769
+ cmd=$(__symit::command)
770
+ __lib::command::print "${cmd}"
771
+ eval "${cmd}"
772
+ code=$?; [[ ${code} != 0 ]] && return $(__symit::exit ${code})
773
+ changed_count=$(( ${changed_count} + 1))
774
+ fi
775
+ fi
776
+ }
777
+
778
+ function symit() {
779
+ __lib::stdout::configure
780
+ __symit::run $@
781
+ }