summaryrefslogtreecommitdiff
path: root/recert
blob: cc746b375f24986d277b17cfddc528e29eabb49d (plain)
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
#!/usr/bin/env bash

single=0 # merge the certs into a single cert
force=0 # if to skip similariaty checks or not
quiet=0 # should i shut up?!?!? :<
cert='cert.pem' # where the public cert should go
key='cert.key' # where the private cert should go
domain='localhost' # the domain to copy certs from

email="freya@freyacat.org"

status=0

usage() {
	printf "usage: recert [-hsfq] [-d DOMAIN] [-c CERT] [-k KEY]\n\n"
	printf "\t-h\t\tshow the help message\n"
	printf "\t-s\t\tcombine the certs into a single cert\n"
	printf "\t-f\t\tskip cert equal checks (force)\n"
	printf "\t-q\t\tquiet output\n"
	printf "\t-d DOMAIN\tthe domain name to recert\n"
	printf "\t-c CERT\t\tthe destination path for the cert\n"
	printf "\t-k KEY\t\tthe destination path for the key (no -s)\n"
}

hash() {
	if [ -f "$1" ]; then
		sha3sum "$1" | awk '{ print $1 }';
	fi
}

letscert() {
	args=(--non-interactive --agree-tos --no-eff-email --email "$email")
	certbot delete \
		$args \
		--cert-name "$domain"
	certbot certonly \
		$args \
		--preferred-chain "ISRG Root X1" \
		--key-type rsa \
		--webroot \
		--webroot-path "/var/www/html" \
		--domains "$1"
	status=1
}

recert_log() {
	if [ $quiet = 0 ]; then
		printf "$*" 1>&2
	fi
}

chk_command() {
	if ! command -v "$1" > /dev/null; then
		>&2 echo "error: command '$1' could not be found"
		exit 1
	fi
}

while getopts ":hsfqd:c:k:" arg > /dev/null; do
	case $arg in
		h)
			usage
			exit 0
			;;
		s)
			single=1
			;;
		f)
			force=1
			;;
		q)
			quiet=1
			;;
		d)
			domain=${OPTARG}
			;;
		c)
			cert=${OPTARG}
			;;
		k)
			key=${OPTARG}
			;;
		?)
			echo "unknown option"
			exit 1
			;;
	esac
done

chk_command "getopts"
chk_command "certbot"
chk_command "openssl"

if [ ! "$cert" = "cert.pem" ] && [ "$key" = "cert.key" ]; then
	name=${cert%.*}
	key="$name.key"
fi

# Step 1: make sure letsencrypt certs exist (create if not)
lets_root="/etc/letsencrypt/live"
lets_cert="$lets_root/$domain/fullchain.pem"
lets_key="$lets_root/$domain/privkey.pem"
if [ ! -f "$lets_cert" ] && [ ! -f "$lets_key" ]; then
	letscert "$domain"
fi

# Step 2: make sure certs wont expire soon (create if will)
if openssl x509 -checkend 604800 -noout -in "$lets_cert" > /dev/null; then
	# certificate is good, only update if forced
	if [ $force = 1 ]; then
		rm "$lets_root"/*
		rmdir "$lets_root"
		recert_log "renewing... "
		letscert "$domain"
	fi
else
	recert_log "renewing... "
	letscert "$domain"
fi

# Step 3: store lets encrypt cert into tmp file
tmp=$(mktemp)
if [ $single = 1 ]; then
	{
		cat "$lets_cert";
		echo;
		cat "$lets_key";
	} >> "$tmp"
fi

# Setup 4: get hashes
current_hash=""
if [ -f "$cert" ]; then
	current_hash=$(md5sum "$cert" | cut -f 1 -d " ")
else
	current_hash="FORCE"
fi

new_hash=""
if [ $single = 1 ]; then
	new_hash=$(md5sum "$tmp" | cut -f 1 -d " ")
else
	new_hash=$(md5sum "$lets_cert" | cut -f 1 -d " ")
fi

# Step 5: copy if hases out of date
if [ "$current_hash" != "$new_hash" ]; then
	recert_log "copied certs\n"
	if [ $single = 1 ]; then
		cp "$tmp" "$cert"
	else
		cp "$lets_cert" "$cert"
		cp "$lets_key" "$key"
	fi
	status=1
else
	recert_log "up to date\n"
fi

# Cleanup
rm "$tmp"

exit "$status"