sym 2.8.0 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +30 -31
- data/.envrc +7 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +150 -928
- data/.travis.yml +16 -26
- data/CHANGELOG.md +206 -167
- data/Gemfile +1 -0
- data/README.adoc +650 -0
- data/Rakefile +9 -3
- data/bin/{sym.completion → sym.completion.bash} +9 -14
- data/bin/sym.symit.bash +781 -0
- data/codecov.yml +29 -0
- data/design/sym-help.png +0 -0
- data/exe/keychain +1 -1
- data/exe/sym +5 -2
- data/lib/ruby_warnings.rb +7 -0
- data/lib/sym.rb +1 -7
- data/lib/sym/app.rb +1 -1
- data/lib/sym/app/args.rb +3 -2
- data/lib/sym/app/cli.rb +1 -2
- data/lib/sym/app/cli_slop.rb +1 -1
- data/lib/sym/app/commands.rb +1 -1
- data/lib/sym/app/commands/base_command.rb +1 -1
- data/lib/sym/app/commands/bash_completion.rb +20 -8
- data/lib/sym/app/commands/open_editor.rb +1 -1
- data/lib/sym/app/commands/password_protect_key.rb +4 -4
- data/lib/sym/app/commands/show_examples.rb +1 -1
- data/lib/sym/app/input/handler.rb +7 -1
- data/lib/sym/app/keychain.rb +15 -9
- data/lib/sym/app/output/noop.rb +2 -1
- data/lib/sym/app/password/cache.rb +1 -1
- data/lib/sym/app/password/providers.rb +2 -3
- data/lib/sym/app/private_key/decryptor.rb +2 -2
- data/lib/sym/app/private_key/detector.rb +4 -7
- data/lib/sym/application.rb +6 -11
- data/lib/sym/constants.rb +28 -13
- data/lib/sym/data/wrapper_struct.rb +20 -12
- data/lib/sym/errors.rb +11 -2
- data/lib/sym/extensions/instance_methods.rb +7 -8
- data/lib/sym/extensions/stdlib.rb +0 -1
- data/lib/sym/extensions/with_retry.rb +1 -1
- data/lib/sym/extensions/with_timeout.rb +1 -1
- data/lib/sym/version.rb +30 -5
- data/sym.gemspec +35 -35
- metadata +88 -71
- data/.codeclimate.yml +0 -30
- data/README.md +0 -623
- data/bin/sym.symit +0 -565
- 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 = ->
|
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=$(
|
14
|
+
bash_version=$(bash --version | awk '{FS="version"}{print $4}')
|
15
15
|
bash_version=${bash_version:0:1}
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
data/bin/sym.symit.bash
ADDED
@@ -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
|
+
}
|