-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathrenew.go
executable file
·143 lines (121 loc) · 3.04 KB
/
renew.go
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
package acmewrapper
import (
"errors"
"fmt"
"time"
"github.com/xenolf/lego/acme"
)
// http://stackoverflow.com/questions/15323767/does-golang-have-if-x-in-construct-similar-to-python
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
// checks if the two arrays of strings contain the same elements
func arraysMatch(a []string, b []string) bool {
if len(a) != len(b) {
return false
}
for _, i := range a {
if !stringInSlice(i, b) {
return false
}
}
return true
}
func getCertError(errmap map[string]error) error {
if len(errmap) == 0 {
return nil
}
// Check if the error is actually a TOS error (meaning we need
// to agree to the TOS again)
for _, err := range errmap {
if _, ok := err.(acme.TOSError); ok {
return err
}
}
// Nope, return the full error
return fmt.Errorf("%v", errmap)
}
// Renew generates a new certificate
func (w *AcmeWrapper) Renew() (err error) {
if w.Config.RenewCallback != nil {
w.Config.RenewCallback()
}
w.Lock()
defer w.Unlock()
if w.Config.AcmeDisabled {
return errors.New("Can't renew cert when ACME is disabled")
}
// TODO: In the future, figure out how to get renewals working with
// the information we have
cert, errmap := w.client.ObtainCertificate(w.Config.Domains, true, nil, false)
err = getCertError(errmap)
if err != nil {
// If it is not a TOS error, fail
if _, ok := err.(acme.TOSError); !ok {
return err
}
// There are new TOS
// TODO: update registration with new TOS
if !w.Config.TOSCallback(w.registration.TosURL) {
return errors.New("Did not accept new TOS")
}
err = w.client.AgreeToTOS()
if err != nil {
return err
}
// We agreed to new TOS. try again
cert, errmap = w.client.ObtainCertificate(w.Config.Domains, true, nil, false)
err = getCertError(errmap)
if err != nil {
return err
}
}
crt, err := tlsCert(cert)
if err != nil {
return err
}
// Write the certs to file if we are using file-backed stuff
if w.Config.TLSCertFile != "" {
w.writeCert(w.Config.TLSCertFile, w.Config.TLSKeyFile, cert)
}
w.certmutex.Lock()
w.cert = crt
w.certmutex.Unlock()
return nil
}
// backgroundExpirationChecker is exactly that - it runs in the background
// and ensures that messages regarding certificate expiration as well as
// any renewals if ACME is configured are run on time.
func backgroundExpirationChecker(w *AcmeWrapper) {
logf("[acmewrapper] Started background expiration checker\n")
for {
time.Sleep(w.Config.RenewCheck)
logf("[acmewrapper] Checking if cert needs update...\n")
if w.CertNeedsUpdate() {
logf("[acmewrapper] ...yes it does\n")
for {
if !w.CertNeedsUpdate() {
break
}
if !w.Config.AcmeDisabled {
err := w.Renew()
if err != nil && w.Config.RenewFailedCallback != nil {
w.Config.RenewFailedCallback(err)
}
if err != nil {
logf("[acmewrapper] Cert update renewal failed!")
}
}
if !w.CertNeedsUpdate() {
break
}
time.Sleep(w.Config.RetryDelay)
}
}
}
}