---
I originally wanted to deal with certificates via SNI, but it seemed pretty
unworkable without quite a lot more complexity and dependencies. This patch
instead adds some stuff to certs.fish to make it easy to add new domains to the
existing certificate (without breaking TOFU)
certs.fish | 84 ++++++++++++++++++++++++++++++++++++++-----------
src/cgi.fish | 24 ++++++++++++--
src/config.fish | 7 +++--
3 files changed, 93 insertions(+), 22 deletions(-)
diff --git a/certs.fish b/certs.fish
index 87c09d1..4790240 100755
--- a/certs.fish
+++ b/certs.fish
@@ -1,28 +1,76 @@
#!/usr/bin/env fish
+# -a or --add to add domains instead of generating a new certificate
+argparse 'a/add=+' -- $argv
+
cd (dirname (status current-filename))/certs; or exit
set days 10000 # 27 years
-if test -f key.pem
- echo 'Warning! If you have already generated keys, they will be overwritten.'
- echo 'If you continue, you will fail Trust On First Use, and some browsers may'
- echo 'be unhappy with your site.'
- echo 'If you have not yet published your site, you can ignore this warning.'
+if ! test "$_flag_add"
+ if test -f key.pem
+ echo 'Warning! If you have already generated keys, they will be overwritten.'
+ echo 'If you continue, you will fail Trust On First Use, and some browsers may'
+ echo 'be unhappy with your site.'
+ echo 'If you have not yet published your site, you can ignore this warning.'
+ echo
+ end
+
+ echo 'To generate certificatates, enter the domain name that your site will be'
+ echo 'eventually published on. If you don\'t care, you can enter nothing.'
+ echo -n 'Example input: '; set_color cyan; echo 'an-excellent.website'
+ read domain -P 'domain name > '
echo
-end
-echo 'To generate certificatates, enter the domain name that your site will be'
-echo 'eventually published on. If you don\'t care, you can enter nothing.'
-echo -n 'Example input: '; set_color cyan; echo 'an-excellent.website'
-read domain -P 'domain name > '
-echo
+ # Country, state, locality, organisation, unit, domain name, email
+ echo -en ".\n.\n.\n.\n.\n$domain\n.\n" | \
+ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days $days -nodes \
+ ; or exit
+
+ echo
+ echo
+ echo 'Everything appears to be okay.'
+else
+ # check a key actually exists
+
+ if ! test -f "key.pem"
+ echo "You need to create a key before you can add domains to it!"
+ exit 1
+ end
+
+ # Get any existing Common Name
+ set cn (openssl x509 -noout -subject -in cert.pem | string match -r 'CN *= *([^ ,]*)')[2]
+
+ # Get any existing Subject Alternative Name(s)
+ set san (openssl x509 -in cert.pem -noout -ext subjectAltName | grep -v '^X509' | string trim)
-# Country, state, locality, organisation, unit, domain name, email
-echo -en ".\n.\n.\n.\n.\n$domain\n.\n" | \
- openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days $days -nodes \
- ; or exit
+ # add new domains
+ for dom in $_flag_add
+ if test $san
+ set san "$san, DNS:$dom"
+ else
+ set san "DNS:$dom"
+ end
+ end
-echo
-echo
-echo 'Everything appears to be okay.'
+ # some clients (at least amfora) don't seem to like certs that use both CN and SAN,
+ # so make sure the CN is in both of them
+ if ! string match -rq "DNS:$cn"'($|,)' -- $san
+ set san "DNS:$cn, $san"
+ end
+
+ echo "This key will now be valid for: '$san'"
+ read -P "Ok? (y/N) " yn
+
+ if string match -r '^[Yy]' -- $yn
+ openssl req -x509 -key key.pem -config \
+ (begin; \
+ cat /etc/ssl/openssl.cnf; \
+ echo "[ subject_alt_name ]"; \
+ echo "subjectAltName = $san"; \
+ end | psub) \
+ -extensions subject_alt_name \
+ -subj "/CN=$cn" \
+ -out cert.pem
+ end
+end
diff --git a/src/cgi.fish b/src/cgi.fish
index 1f66a18..d06d4fc 100644
--- a/src/cgi.fish
+++ b/src/cgi.fish
@@ -45,8 +45,28 @@ if test $req_query = "source=1"
set source_mode true
end
-# future host handling code here?
-# ...
+server_echo $req_host
+# host handling
+set serve_root (string match -r -- '^'$req_host':(.*)' $serve_roots)[2]
+
+# if the host is not explicitly configured, use the default
+if test -z $serve_root
+ set serve_root (string match -r -- '^default:(.*)' $serve_roots)[2]
+end
+
+server_echo $serve_root
+
+# if it's still empty, fail
+if test -z $serve_root
+ gem_header 59 "Bliz server: no server root configured for $req_host"
+ exit
+end
+
+# if the path doesn't exist, fail
+if ! test -d $serve_root
+ gem_header 59 "Bliz server: configured server root does not exist on host"
+ exit
+end
# normalise path to remove /./, some broken clients add it
# `x` is added to the start and end of the string so that leading and trailing slashes won't be removed
diff --git a/src/config.fish b/src/config.fish
index 8e6c474..cd690d6 100644
--- a/src/config.fish
+++ b/src/config.fish
@@ -19,13 +19,16 @@ set spartan_port
# Optional - remove this value to not serve data.
set mercury_port 1964
-set serve_root serve
+set serve_roots "default:serve" # add vhosts in the form "example1.com:/path/to/root" "example2.com:/another/root" etc
set serve_index # add arguments here for default index preference
set debug_server_echo false
source personal/config.fish
+
# Normalise
-set serve_root (string trim -r -c / -- $serve_root)
+for i in (seq (count serve_roots))
+ set serve_roots[$i] (string trim -r -c / -- $serve_roots[$i])
+end
--
2.35.1