summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2020-09-04 16:21:58 -0400
committerAndrew Cady <d@jerkface.net>2020-09-04 16:21:58 -0400
commit03be69d4985731e10c2c168a8f50431eff18a0f7 (patch)
tree71db926c8c2f72f75547a6db7c48a625a74e68a8
initial commit
-rw-r--r--selfpublish.sh267
1 files changed, 267 insertions, 0 deletions
diff --git a/selfpublish.sh b/selfpublish.sh
new file mode 100644
index 0000000..8a17c67
--- /dev/null
+++ b/selfpublish.sh
@@ -0,0 +1,267 @@
1#!/bin/sh
2set -e
3
4DEFAULT_AUTH_TYPE=ed25519
5
6force()
7{
8 [ "$FORCE" ]
9}
10
11in_group()
12{
13 local g
14 for g in $(groups)
15 do
16 [ "$g" = "$1" ] && return
17 done
18 false
19}
20
21as_root()
22{
23 if [ "$(id -u)" = 0 ]
24 then
25 "$@"
26 elif in_group sudo
27 then
28 sudo "$@"
29 else
30 su -c "$*"
31 fi
32}
33
34apt_install()
35{
36 as_root apt-get install "$@"
37}
38
39dpkg_install()
40{
41 as_root dpkg -i "$@"
42}
43
44control_file()
45{
46 cat <<EOF
47Package: selfpublish-dot-sh-deps
48Depends: apache2 (>= 2.4.46), libssl1.1 (>= 1.1.1d)
49Description: selfpublish.sh dependency package
50 This package depends on the dependencies of the
51 selfpublish.sh script, and is installed by that
52 script to self-satisfy those dependencies.
53
54EOF
55}
56
57equivocate()
58{
59 dpkg-query -s selfpublish-dot-sh-deps >/dev/null 2>&1 && return || true
60 which equivs-build >/dev/null 2>&1 || apt_install equivs
61 (
62 destdir=$(mktemp -d)
63 cd "$destdir"
64 control_file > ./control
65 equivs-build ./control >/dev/null 2>&1
66 dpkg_install selfpublish-dot-sh-deps_1.0_all.deb
67 )
68}
69
70ssh_keytag_to_path_fragment()
71{
72 case "$1" in
73 ssh-dss) echo dsa ;;
74 ecdsa-sha2-nistp256) echo ecdsa ;;
75 ssh-rsa|ssh-ed25519) echo ${1#ssh-} ;;
76 *) return 1 ;;
77 esac
78}
79
80path_fragment_to_ssh_keytag()
81{
82 case "$1" in
83 ssh-dss|ecdsa-sha2-nistp256|ssh-rsa|ssh-ed25519) echo $1;;
84 dss|rsa|ed25519) echo ssh-$1 ;;
85 dsa) echo ssh-dss ;;
86 ecdsa) echo ecdsa-sha2-nistp256 ;;
87 *) return 1 ;;
88 esac
89}
90
91get_dyndns_domain()
92{
93 fragment=$(ssh_keytag_to_path_fragment "$1") || return
94
95 host_keyfile=/etc/ssh/ssh_host_${fragment}_key
96 user_keyfile=$HOME/.ssh/id_${fragment}
97
98 set -- -q dyndns@cryptonomic.net
99
100 if [ -r "$host_keyfile" ]
101 then
102 set -- ssh -i "$host_keyfile" "$@"
103
104 elif in_group sudo
105 then
106 set -- sudo ssh -i "$host_keyfile" "$@"
107
108 elif [ -r "$user_keyfile" ]
109 then
110 set -- ssh -i "$user_keyfile" "$@"
111
112 else
113 set -- ssh "$@"
114 fi
115
116 "$@"
117}
118
119enable_apache_modules()
120{
121 for MODULE in $APACHE_MODULES
122 do
123 a2enmod $MODULE >/dev/null
124 done
125}
126
127site_conf_template()
128{
129cat <<END
130<MDomain $DOMAIN>
131 MDContactEmail webmaster@$DOMAIN
132 MDCertificateAgreement accepted
133 MDRequireHttps temporary
134</MDomain>
135<VirtualHost *:80>
136 ServerName $DOMAIN
137 ServerAlias ${DOMAIN}.
138 Redirect / https://$DOMAIN
139</VirtualHost>
140
141<VirtualHost *:443>
142 ServerName $DOMAIN
143
144 ServerAdmin webmaster@$DOMAIN
145 SSLEngine on
146
147 ErrorLog /srv/$DOMAIN/logs/error.log
148 CustomLog /srv/$DOMAIN/logs/access.log combined
149
150 <Location "/server-status">
151 SetHandler server-status
152 </Location>
153
154 DocumentRoot /srv/$DOMAIN/public_html/
155 <Directory /srv/$DOMAIN/public_html>
156 Options Indexes FollowSymLinks MultiViews Includes
157
158 IndexOrderDefault Descending Date
159 IndexOptions +IgnoreCase FancyIndexing
160 IndexOptions +HTMLTable SuppressDescription
161 IndexStyleSheet /css/autoindex.css
162 IndexIgnore /unindexed /HEADER.html /css /images
163
164 # Using an absolute url for header
165 HeaderName /HEADER.html
166
167 XBitHack on
168 AllowOverride None
169 Require all granted
170 </Directory>
171
172</VirtualHost>
173END
174}
175
176wait_for_certificate_issuance()
177{
178 local f state
179 f=/etc/apache2/md/domains/"$1"/md.json
180 while true
181 do
182 if [ -e "$f" ]
183 then
184 state=$(sed -ne 's/^ *"state": *\([0-9]\+\),/\1/p' "$f")
185
186 if [ "$state" = 2 ]
187 then
188 return
189 fi
190 fi
191 sleep 1
192 done
193}
194
195install_apache_site()
196{
197 if [ -e "$SITE_CONF" ] && ! force
198 then
199 return
200 fi
201
202 for DIR in $APACHE_SITE_DIRS
203 do
204 mkdir -p "$SITE_DIR"/"$DIR"
205 done
206
207 local tmp
208 tmp=$(mktemp "$SITE_CONF".XXXXXX)
209
210 site_conf_template > "$tmp"
211 mv -T "$tmp" "$SITE_CONF" || { rm -f "$tmp"; false; }
212 a2ensite "$DOMAIN" >/dev/null
213}
214
215install_self_to_site()
216{
217 SOURCE_BASENAME=${0##*/}
218 [ -d "$SITE_DIR"/public_html ] || return
219 dst=$SITE_DIR/public_html/$SOURCE_BASENAME
220 src=$0
221 [ -e "$src" ] || return 0
222 if [ ! "$src" -ef "$dst" ]
223 then
224 cp -Tuv "$src" "$dst" >&2
225 cp -Tuv "$src" "$dst".txt >&2
226 fi
227}
228
229check_tls()
230{
231 curl -s -S -I https://"$1" >/dev/null
232}
233
234equivocate
235
236APACHE_MODULES='status md rewrite ssl include'
237APACHE_SITE_DIRS='logs public_html'
238
239AUTH_TYPE=$(path_fragment_to_ssh_keytag "${1:-$DEFAULT_AUTH_TYPE}")
240DYNDNS=$(get_dyndns_domain "$AUTH_TYPE")
241DOMAIN=${DYNDNS%% *}
242SITE_DIR=/srv/$DOMAIN
243SITE_CONF=/etc/apache2/sites-available/$DOMAIN.conf
244
245case "$DOMAIN" in
246 *."$AUTH_TYPE".cryptonomic.net) ;;
247 *)
248 printf 'Error: %s\n' "Unexpected domain returned by server: $DOMAIN"
249 exit 1 ;;
250esac
251
252if ! check_tls "$DOMAIN" || force
253then
254 equivocate
255 enable_apache_modules
256 install_apache_site
257 install_self_to_site
258 systemctl restart apache2
259 wait_for_certificate_issuance "$DOMAIN"
260 systemctl reload apache2
261else
262 install_self_to_site
263fi
264
265check_tls "$DOMAIN"
266printf '%s\n' "https://$DOMAIN/selfpublish.sh"
267