...
1
2
3
4
5 package autocert
6
7 import (
8 "context"
9 "crypto"
10 "sync"
11 "time"
12 )
13
14
15 const renewJitter = time.Hour
16
17
18
19 type domainRenewal struct {
20 m *Manager
21 ck certKey
22 key crypto.Signer
23
24 timerMu sync.Mutex
25 timer *time.Timer
26 timerClose chan struct{}
27 }
28
29
30
31
32
33 func (dr *domainRenewal) start(exp time.Time) {
34 dr.timerMu.Lock()
35 defer dr.timerMu.Unlock()
36 if dr.timer != nil {
37 return
38 }
39 dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
40 }
41
42
43
44 func (dr *domainRenewal) stop() {
45 dr.timerMu.Lock()
46 defer dr.timerMu.Unlock()
47 for {
48 if dr.timer == nil {
49 return
50 }
51 if dr.timer.Stop() {
52 dr.timer = nil
53 return
54 } else {
55
56
57 timerClose := make(chan struct{})
58 dr.timerClose = timerClose
59 dr.timerMu.Unlock()
60 <-timerClose
61 dr.timerMu.Lock()
62 }
63 }
64 }
65
66
67
68 func (dr *domainRenewal) renew() {
69 dr.timerMu.Lock()
70 defer dr.timerMu.Unlock()
71 if dr.timerClose != nil {
72 close(dr.timerClose)
73 dr.timer, dr.timerClose = nil, nil
74 return
75 }
76
77 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
78 defer cancel()
79
80 next, err := dr.do(ctx)
81 if err != nil {
82 next = renewJitter / 2
83 next += time.Duration(pseudoRand.int63n(int64(next)))
84 }
85 testDidRenewLoop(next, err)
86 dr.timer = time.AfterFunc(next, dr.renew)
87 }
88
89
90
91 func (dr *domainRenewal) updateState(state *certState) {
92 dr.m.stateMu.Lock()
93 defer dr.m.stateMu.Unlock()
94 dr.key = state.key
95 dr.m.state[dr.ck] = state
96 }
97
98
99
100
101
102
103
104
105
106 func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
107
108
109 if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
110 next := dr.next(tlscert.Leaf.NotAfter)
111 if next > dr.m.renewBefore()+renewJitter {
112 signer, ok := tlscert.PrivateKey.(crypto.Signer)
113 if ok {
114 state := &certState{
115 key: signer,
116 cert: tlscert.Certificate,
117 leaf: tlscert.Leaf,
118 }
119 dr.updateState(state)
120 return next, nil
121 }
122 }
123 }
124
125 der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
126 if err != nil {
127 return 0, err
128 }
129 state := &certState{
130 key: dr.key,
131 cert: der,
132 leaf: leaf,
133 }
134 tlscert, err := state.tlscert()
135 if err != nil {
136 return 0, err
137 }
138 if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
139 return 0, err
140 }
141 dr.updateState(state)
142 return dr.next(leaf.NotAfter), nil
143 }
144
145 func (dr *domainRenewal) next(expiry time.Time) time.Duration {
146 d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
147
148 n := pseudoRand.int63n(int64(renewJitter))
149 d -= time.Duration(n)
150 if d < 0 {
151 return 0
152 }
153 return d
154 }
155
156 var testDidRenewLoop = func(next time.Duration, err error) {}
157
View as plain text