/
curl-bashenv
executable file
·266 lines (215 loc) · 7.91 KB
/
curl-bashenv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#!/bin/bash
#set -v
set -e
set -o pipefail
test -n "$DEBUG" && set -x
# Programs we use
AWK="${AWK:-awk}"
BASENAME="${BASENAME:-basename}"
CAT="${CAT:-cat}"
CP="${CP:-cp}"
CURL="${CURL:-curl}"
GIT="${GIT:-git}"
GREP="${GREP:-grep}"
LS="${LS:-ls}"
LN="${LN:-ln}"
MKDIR="${MKDIR:-mkdir}"
MV="${MV:-mv}"
SCP="${SCP:-scp}"
SED="${SED:-sed}"
SSH="${SSH:-ssh}"
SSH_KEYGEN="${SSH_KEYGEN:-ssh-keygen}"
TR="${TR:-tr}"
# Config vars
CURLBASHENV_ROOT="${CURLBASHENV_ROOT:-$HOME/.curl-bashenv}"
BACKUP_DIR="${BACKUP_DIR:-${CURLBASHENV_ROOT}/backup}"
SETUP_DIR="${SETUP_DIR:-${CURLBASHENV_ROOT}/setup}"
SETUP_STEPS="${SETUP_STEPS:-ssh shdotfiles gitconfig}"
SHDOTFILES="${SHDOTFILES:-bashrc bash_profile}"
# TODO:
# "ALL" handling in the gitrepo case (with directories?)
# "PLUGIN" support
# These args come from:
# https://stribika.github.io/2015/01/04/secure-secure-shell.html
SSH_KEYGEN_ARGS="${SSH_KEYGEN_ARGS:- -t ed25519 -o -a 100}"
# However, they're not supported (specifically, -o and the elliptical curve
# key types) on current versions of RHEL, Mac OS, and a bunch of other common
# OpenSSH installations, so for now, use the next best thing:
SSH_KEYGEN_ARGS="${SSH_KEYGEN_ARGS:- -t rsa -b 4096 -a 100}"
SOURCE=${SOURCE:-""}
SOURCE_GIT_CLONE_DIR="${SOURCE_GIT_CLONE_DIR:-${SETUP_DIR}/gitrepo}"
GIT_CLONE_ARGS="${GIT_CLONE_ARGS:-}"
# Standard test doesn't work here, since the DOTFILE_PREFIX _could_ (and
# in the way we use it, often is) empty, BUT defined... as empty.
if [ -z ${DOTFILE_PREFIX+x} ]; then
DOTFILE_PREFIX="."
fi
# BASE_URL="define other steps"
# source: copy source key here
# create: create a local key
# createauthorize: create a local key and copy it to the source
SSH_KEY_MODE=${SSH_KEY_MODE:-create}
SSH_KEY_NAME=${SSH_KEY_NAME:-~/.ssh/id_dsa}
SSH_PUB_KEY_NAME=${SSH_PUB_KEY_NAME:-${SSH_KEY_NAME}.pub}
# Nabbed from: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
function join { local IFS="$1"; shift; echo "$*"; }
function assert() {
echo "$1" > /dev/stderr
exit -1
}
function error_out() {
echo "$1" > /dev/stderr
test -n "$2" && exit $2
exit 1
}
# Always assumes the dest_file has a '.'
function symlink_gitrepo_file() {
test -z "$1" && assert "symlink_gitrepo_file: first arg empty"
source_file="${SOURCE_GIT_CLONE_DIR}/${DOTFILE_PREFIX}$1"
dest_file="$HOME/.$1"
test -e "$dest_file" && $MV "$dest_file" "${BACKUP_DIR}"
$LN -s "$source_file" "$dest_file"
}
function symlink_sourcehost_file() {
test -z "$1" && assert "symlink_sourcehost_file: first arg empty"
source_file="${SETUP_DIR}/$1"
dest_file="$HOME/$1"
test -e "$dest_file" && $MV "$dest_file" "${BACKUP_DIR}"
$LN -s "$source_file" "$dest_file"
}
function setup_sourcehost_ssh() {
local sshBackupDir="${BACKUP_DIR}/.ssh"
keyMode=$(echo $SSH_KEY_MODE | $TR "[:upper:]" "[:lower:]")
if [ "$keyMode" != "create" ] &&
[ "$keyMode" != "source" ] &&
[ "$keyMode" != "createauthorize" ]; then
error_out "Invalid SSH_KEY_MODE '$SSH_KEY_MODE'; must be source, create, or createauthorize"
fi
local sourceHostname="$(echo $SOURCE | $SED -e 's:\(.*\)@\(.*\):\2:')"
if test -z "$($GREP "^$sourceHostname" $HOME/.ssh/known_hosts)"; then
$SSH $SOURCE "bash -c 'for f in /etc/ssh/ssh_host_*_key.pub; do test -f \$f && $SSH_KEYGEN -l -f \$f; done'"
echo "Validate one of the keys displayed above matches the key you accepted; if not, you were just MITM'd! Use ctrl-c to stop $0"
read
fi
if test -n "$(echo $keyMode | $GREP create)"; then
test -e $SSH_KEY_NAME || $SSH_KEYGEN $SSH_KEYGEN_ARGS -f $SSH_KEY_NAME
elif [ "$keyMode" == "source" ]; then
test -e $SSH_KEY_NAME || $MV $SSH_KEY_NAME $sshBackupDir
test -e $SSH_PUB_KEY_NAME || $MV $SSH_PUB_KEY_NAME $sshBackupDir
$SCP $SOURCE:~/.ssh/\{$SSH_KEY_NAME,$SSH_PUB_KEY_NAME\} $SETUP_DIR
$MV $SETUP_DIR/$($BASENAME $SSH_KEY_NAME) $HOME/.ssh
$MV $SETUP_DIR/$($BASENAME $SSH_PUB_KEY_NAME) $HOME/.ssh
else
assert "setup_ssh(): UNREACHABLE."
fi
if [ "$keyMode" == "createauthorize" ]; then
if ! test -e $SSH_PUB_KEY_NAME; then
error_out "Couldn't find $SSH_PUB_KEY_NAME; bailing"
fi
# Yes, I know ssh-copy-id exists; we do this because for some
# reason, ssh-copy-id is not available on Macs...
local ssh_pub_key_contents=$($CAT $SSH_PUB_KEY_NAME)
$SSH $SOURCE "echo $ssh_pub_key_contents >> ~/.ssh/authorized_keys"
fi
# TODO: make this a var too.
# cp config, known_hosts, authorized keys
$SCP ${SOURCE}:~/.ssh/\{config,authorized_keys,known_hosts\} $SETUP_DIR/
test -d $sshBackupDir || $MKDIR $sshBackupDir
test -e $HOME/.ssh/config && $MV $HOME/.ssh/config $sshBackupDir
local sshFiles="$($LS $HOME/.ssh/{authorized_keys,known_hosts} 2> /dev/null)"
test -n "$sshFiles" && $CP $sshFiles $sshBackupDir
$MV ${SETUP_DIR}/config $HOME/.ssh
$CAT ${SETUP_DIR}/authorized_keys >> $HOME/.ssh/authorized_keys
$CAT ${SETUP_DIR}/known_hosts >> $HOME/.ssh/known_hosts
return 0
}
function setup_gitrepo_ssh() {
keyMode=$(echo $SSH_KEY_MODE | $TR "[:upper:]" "[:lower:]")
if [ "$keyMode" != "create" ] &&
[ "$keyMode" != "source" ] &&
[ "$keyMode" != "createauthorize" ]; then
error_out "Invalid SSH_KEY_MODE '$SSH_KEY_MODE'; must be source, create, or createauthorize"
fi
clone_source_gitrepo
repo_ssh_dir="${DOTFILE_PREFIX}ssh"
if [ -d "$SOURCE_GIT_CLONE_DIR/$repo_ssh_dir" ]; then
test -e $HOME/.ssh && $MV $HOME/.ssh $BACKUP_DIR
symlink_gitrepo_file ssh
else
echo "SSH config directory $repo_ssh_dir not found in git repo." > /dev/stderr
return 0
fi
if test -n "$(echo $keyMode | $GREP create)"; then
repo_key_file="$SOURCE_GIT_CLONE_DIR/$repo_ssh_dir/${SSH_KEY_NAME}"
if test -e "$repo_key_file"; then
echo "SSH key $repo_file_file exists, but key creation requested; SKIPPING KEY CREATION" > /dev/stderr
return 1
fi
$SSH_KEYGEN $SSH_KEYGEN_ARGS -f $SSH_KEY_NAME
fi
if [ "$keyMode" == "createauthorize" ]; then
if ! test -e $SSH_PUB_KEY_NAME; then
error_out "Couldn't find $SSH_PUB_KEY_NAME; bailing"
fi
auth_host="$(echo $SOURCE | $AWK -F: '{ print $1 }')"
if test -n "$(echo $auth_host | $GREP -i 'github.com$')"; then
echo "Trying to publish your public key to github is unlikely to work, but we'll try anyway." > /dev/stderr
fi
# Yes, I know ssh-copy-id exists; we do this because for some
# reason, ssh-copy-id is not available on Macs...
local ssh_pub_key_contents=$($CAT $SSH_PUB_KEY_NAME)
$SSH $auth_host "echo $ssh_pub_key_contents >> ~/.ssh/authorized_keys"
fi
return 0
}
function setup_sourcehost_shdotfiles() {
local prefixed_dotfiles=()
for f in $SHDOTFILES; do
local prefixed_file=${DOTFILE_PREFIX}$f
prefixed_dotfiles+=($prefixed_file)
done
local dotfile_list=$(join , ${prefixed_dotfiles[*]})
$SCP $SOURCE:~/{$dotfile_list} ${SETUP_DIR}/
for f in $prefixed_dotfiles; do
symlink_sourcehost_file $f
done
return 0
}
function setup_sourcehost_gitconfig() {
$SCP ${SOURCE}:~/.gitconfig ${SETUP_DIR}/
symlink_sourcehost_file .gitconfig
}
function setup_gitrepo_gitconfig() {
clone_source_gitrepo
symlink_gitrepo_file gitconfig
}
function clone_source_gitrepo() {
if ! test -d "${SOURCE_GIT_CLONE_DIR}/.git"; then
if test -e "$SOURCE_GIT_CLONE_DIR"; then
error_out "SOURCE_GIT_CLONE_DIR '${SOURCE_GIT_CLONE_DIR}' exists, but is not a git repository; bailing..."
fi
$GIT clone $GIT_CLONE_ARGS $SOURCE $SOURCE_GIT_CLONE_DIR
fi
}
function setup_gitrepo_shdotfiles() {
clone_source_gitrepo
for f in $SHDOTFILES; do
symlink_gitrepo_file $f
done
}
test -z "$SOURCE" && error_out "Environment source must be defined."
echo "Environment source: $SOURCE"
# This isn't a very good test to see if $SOURCE is a Git repo; it grabs
# github in the hostname _or_ .git in the path, i.e. mymachine:/myrepo.git
if [ -n "$(echo $SOURCE | $GREP -i github)" ] ||
[ -n "$(echo $SOURCE | $GREP -i '\.git$')" ]; then
run_mode="gitrepo"
else
run_mode="sourcehost"
fi
$MKDIR -p $BACKUP_DIR || true
$MKDIR -p $SETUP_DIR || true
for step in ${SETUP_STEPS}; do
setup_${run_mode}_${step}
echo "setup_${run_mode}_${step}: $?"
done