1
1
package server
2
2
3
3
import (
4
+ "encoding/json"
5
+ "fmt"
4
6
"log"
5
- "pkg.para.party/certdx/pkg/config"
6
- "pkg.para.party/certdx/pkg/utils"
7
+ "os"
7
8
"slices"
8
9
"strings"
9
10
"sync"
10
11
"sync/atomic"
11
12
"time"
13
+
14
+ "pkg.para.party/certdx/pkg/config"
15
+ "pkg.para.party/certdx/pkg/utils"
12
16
)
13
17
14
18
type CertT struct {
15
- Cert , Key []byte
16
- ValidBefore time.Time
19
+ FullChain []byte `json:"fullChain"`
20
+ Key []byte `json:"key"`
21
+ ValidBefore time.Time `json:"validBefore"`
17
22
}
18
23
19
- type ServerCertCacheEntry struct {
20
- Domains []string
24
+ type ServerCacheFileEntry struct {
25
+ Domains []string `json:"domains"`
26
+ Cert CertT `json:"cert"`
27
+ }
21
28
22
- cert CertT
23
- Mutex sync.Mutex
29
+ type ServerCertCacheEntry struct {
30
+ domains []string
31
+ cert CertT
32
+ mutex sync.Mutex
24
33
25
34
Listening atomic.Bool
26
35
Updated atomic.Pointer [chan struct {}]
27
36
Stop atomic.Pointer [chan struct {}]
28
37
}
29
38
30
39
type ServerCertCacheT struct {
31
- entrys []* ServerCertCacheEntry
32
- mutex sync.Mutex
40
+ entrys []* ServerCertCacheEntry
41
+ mutex sync.Mutex
42
+ updated atomic.Pointer [chan struct {}]
33
43
}
34
44
35
45
var ServerCertCache = & ServerCertCacheT {}
36
46
var Config = & config.ServerConfigT {}
37
47
48
+ func InitCache () error {
49
+ updated := make (chan struct {})
50
+ ServerCertCache .updated .Store (& updated )
51
+
52
+ if err := loadCacheFile (); err != nil {
53
+ return err
54
+ }
55
+
56
+ go func () {
57
+ for {
58
+ <- * ServerCertCache .updated .Load ()
59
+ log .Printf ("[INF] Write domains cache to file" )
60
+
61
+ if err := writeCacheFile (); err != nil {
62
+ log .Printf ("[WRN] Write domains cache to file failed: %s" , err )
63
+ }
64
+ }
65
+ }()
66
+
67
+ return nil
68
+ }
69
+
70
+ func loadCacheFile () error {
71
+ cachePath , exist := getCacheSavePath ()
72
+ if ! exist {
73
+ return nil
74
+ }
75
+
76
+ cfile , err := os .ReadFile (cachePath )
77
+ if err != nil {
78
+ return fmt .Errorf ("open cache file failed: %w" , err )
79
+ }
80
+
81
+ var caches []ServerCacheFileEntry
82
+ err = json .Unmarshal (cfile , & caches )
83
+ if err != nil {
84
+ return fmt .Errorf ("unmarshal cache file failed: %w" , err )
85
+ }
86
+
87
+ for _ , cache := range caches {
88
+ entry := ServerCertCache .GetEntry (cache .Domains )
89
+ entry .mutex .Lock ()
90
+ entry .cert = cache .Cert
91
+ entry .mutex .Unlock ()
92
+ }
93
+
94
+ return nil
95
+ }
96
+
97
+ func writeCacheFile () error {
98
+ ServerCertCache .mutex .Lock ()
99
+ defer ServerCertCache .mutex .Unlock ()
100
+
101
+ var caches []ServerCacheFileEntry
102
+ for _ , entry := range ServerCertCache .entrys {
103
+ entry .mutex .Lock ()
104
+ cache := ServerCacheFileEntry {
105
+ Domains : entry .domains ,
106
+ Cert : entry .cert ,
107
+ }
108
+ entry .mutex .Unlock ()
109
+ caches = append (caches , cache )
110
+ }
111
+
112
+ jsonBytes , err := json .Marshal (caches )
113
+ if err != nil {
114
+ return fmt .Errorf ("failed marshal cache file: %w" , err )
115
+ }
116
+
117
+ cachePath , _ := getCacheSavePath ()
118
+ err = os .WriteFile (cachePath , jsonBytes , 0o600 )
119
+ if err != nil {
120
+ return fmt .Errorf ("failed write cache file: %w" , err )
121
+ }
122
+
123
+ return nil
124
+ }
125
+
38
126
func (s * ServerCertCacheT ) GetEntry (domains []string ) * ServerCertCacheEntry {
39
127
s .mutex .Lock ()
40
128
defer s .mutex .Unlock ()
41
129
for _ , entry := range s .entrys {
42
- if utils .SameCert (domains , entry .Domains ) {
130
+ if utils .SameCert (domains , entry .domains ) {
43
131
return entry
44
132
}
45
133
}
46
134
47
135
entry := & ServerCertCacheEntry {
48
- Domains : domains ,
136
+ domains : domains ,
49
137
}
50
138
entry .Listening .Store (false )
51
139
updated := make (chan struct {})
@@ -57,16 +145,16 @@ func (s *ServerCertCacheT) GetEntry(domains []string) *ServerCertCacheEntry {
57
145
}
58
146
59
147
func (c * ServerCertCacheEntry ) Cert () CertT {
60
- c .Mutex .Lock ()
61
- defer c .Mutex .Unlock ()
148
+ c .mutex .Lock ()
149
+ defer c .mutex .Unlock ()
62
150
return c .cert
63
151
}
64
152
65
153
func (c * ServerCertCacheEntry ) Renew (retry bool ) (bool , error ) {
66
- c .Mutex .Lock ()
67
- defer c .Mutex .Unlock ()
154
+ c .mutex .Lock ()
155
+ defer c .mutex .Unlock ()
68
156
69
- log .Printf ("[INF] Renew cert: %v" , c .Domains )
157
+ log .Printf ("[INF] Renew cert: %v" , c .domains )
70
158
if ! time .Now ().Before (c .cert .ValidBefore ) {
71
159
newValidBefore := time .Now ().Truncate (1 * time .Hour ).Add (Config .ACME .CertLifeTimeDuration )
72
160
@@ -75,27 +163,29 @@ func (c *ServerCertCacheEntry) Renew(retry bool) (bool, error) {
75
163
return false , err
76
164
}
77
165
78
- var cert , key []byte
166
+ var fullchain , key []byte
79
167
if retry {
80
- cert , key , err = acme .RetryObtain (c .Domains , newValidBefore .Add (Config .ACME .RenewTimeLeftDuration ))
168
+ fullchain , key , err = acme .RetryObtain (c .domains , newValidBefore .Add (Config .ACME .RenewTimeLeftDuration ))
81
169
} else {
82
- cert , key , err = acme .Obtain (c .Domains , newValidBefore .Add (Config .ACME .RenewTimeLeftDuration ))
170
+ fullchain , key , err = acme .Obtain (c .domains , newValidBefore .Add (Config .ACME .RenewTimeLeftDuration ))
83
171
}
84
172
if err != nil {
85
173
return false , err
86
174
}
87
175
88
176
c .cert = CertT {
89
177
ValidBefore : newValidBefore ,
90
- Cert : cert ,
178
+ FullChain : fullchain ,
91
179
Key : key ,
92
180
}
93
181
94
- log .Printf ("[INF] Obtained cert: %v" , c .Domains )
182
+ log .Printf ("[INF] Obtained cert: %v" , c .domains )
183
+ newUpdated := make (chan struct {})
184
+ close (* ServerCertCache .updated .Swap (& newUpdated ))
95
185
return true , nil
96
186
}
97
187
98
- log .Printf ("[INF] Cert: %v not expired" , c .Domains )
188
+ log .Printf ("[INF] Cert: %v not expired" , c .domains )
99
189
return false , nil
100
190
}
101
191
@@ -106,13 +196,13 @@ func (c *ServerCertCacheEntry) CertWatchDog() {
106
196
107
197
c .Listening .Store (true )
108
198
for {
109
- log .Printf ("[INF] Server renew: %v" , c .Domains )
199
+ log .Printf ("[INF] Server renew: %v" , c .domains )
110
200
changed , err := c .Renew (true )
111
201
if err != nil {
112
- log .Printf ("[ERR] Failed renew cert %s: %s" , c .Domains , err )
202
+ log .Printf ("[ERR] Failed renew cert %s: %s" , c .domains , err )
113
203
} else if changed {
114
204
newUpdated := make (chan struct {})
115
- log .Printf ("[INF] Notify cert %s updated" , c .Domains )
205
+ log .Printf ("[INF] Notify cert %s updated" , c .domains )
116
206
close (* c .Updated .Swap (& newUpdated ))
117
207
}
118
208
0 commit comments