forked from ayufan/auto-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcertificates.go
135 lines (116 loc) · 2.89 KB
/
certificates.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
package main
import (
"crypto/tls"
"github.com/Sirupsen/logrus"
"os"
"sync"
"time"
)
type Certificates struct {
list map[string]*Certificate
lock sync.RWMutex
}
func (c *Certificates) add(certificate *Certificate) {
if c.list == nil {
c.list = make(map[string]*Certificate)
}
c.list[certificate.Name] = certificate
}
func (c *Certificates) remove(name string) {
delete(c.list, name)
}
func (c *Certificates) load(name string, challenge CertificateChallenge) (tls *tls.Certificate, err error) {
logrus.WithField("name", name).Debugln("Loading certificate...")
// Just in case if certificate was added by other entity
tls = c.find(name)
if tls != nil {
return tls, nil
}
// Create a new certificate
if c.list == nil {
c.list = make(map[string]*Certificate)
}
certificate := c.list[name]
if certificate == nil {
certificate = NewCertificate(name)
c.list[name] = certificate
}
tls = certificate.TLS
// Should we update (re-read?) the certificate?
if !certificate.CanUpdate(time.Minute) {
return
}
// Load the certificate
err = certificate.Load()
tls = certificate.TLS
if !os.IsNotExist(err) {
if err != nil {
logrus.Warningln(err)
}
return
}
// Should we re-request the certificate?
if !certificate.CanUpdate(time.Minute) {
return
}
certificate.Requesting = true
go func() {
err := certificate.Request(challenge)
certificate.Requesting = false
if err != nil {
certificate.log().WithError(err).Warningln("Failed to request a new certificate")
}
}()
return
}
func (c Certificates) find(serverName string) *tls.Certificate {
if certificate, ok := c.list[serverName]; ok && certificate != nil {
if certificate.Requesting && certificate.TLS == nil {
return nil
}
return certificate.TLS
}
return nil
}
func (c Certificates) tick(challenge CertificateChallenge) {
for _, certificate := range c.list {
if certificate.Requesting {
continue
}
if certificate.IsExpiring(*requestBefore) && certificate.CanUpdate(*retryInterval) {
certificate.Requesting = true
go func(certificate *Certificate) {
err := certificate.Request(challenge)
certificate.Requesting = false
if err != nil {
certificate.log().WithError(err).Warningln("Failed to request a new certificate")
}
}(certificate)
}
}
}
func (c *Certificates) Add(certificate *Certificate) {
c.lock.Lock()
defer c.lock.Unlock()
c.add(certificate)
}
func (c *Certificates) Remove(name string) {
c.lock.Lock()
defer c.lock.Unlock()
c.remove(name)
}
func (c *Certificates) Load(name string, challenge CertificateChallenge) (*tls.Certificate, error) {
c.lock.Lock()
defer c.lock.Unlock()
return c.load(name, challenge)
}
func (c Certificates) Find(serverName string) *tls.Certificate {
c.lock.RLock()
defer c.lock.RUnlock()
return c.find(serverName)
}
func (c Certificates) Tick(challenge CertificateChallenge) {
c.lock.RLock()
defer c.lock.RUnlock()
c.tick(challenge)
}