@@ -2,6 +2,7 @@ package wsproxy
2
2
3
3
import (
4
4
"context"
5
+ "maps"
5
6
"sync"
6
7
"sync/atomic"
7
8
"time"
@@ -47,7 +48,7 @@ func NewCryptoKeyCache(ctx context.Context, log slog.Logger, client *wsproxysdk.
47
48
48
49
cache .refreshCtx ,cache .refreshCancel = context .WithCancel (ctx )
49
50
cache .refresher = cache .Clock .AfterFunc (time .Minute * 10 ,cache .refresh )
50
- m ,latest ,err := cache .fetchKeys (ctx )
51
+ m ,latest ,err := cache .cryptoKeys (ctx )
51
52
if err != nil {
52
53
cache .refreshCancel ()
53
54
return nil ,xerrors .Errorf ("initial fetch: %w" ,err )
@@ -100,10 +101,11 @@ func (k *CryptoKeyCache) Verifying(ctx context.Context, sequence int32) (codersd
100
101
return codersdk.CryptoKey {},cryptokeys .ErrClosed
101
102
}
102
103
103
- now := k .Clock .Now ()
104
104
k .keysMu .RLock ()
105
105
key ,ok := k .keys [sequence ]
106
106
k .keysMu .RUnlock ()
107
+
108
+ now := k .Clock .Now ()
107
109
if ok {
108
110
return validKey (key ,now )
109
111
}
@@ -135,11 +137,13 @@ func (k *CryptoKeyCache) Verifying(ctx context.Context, sequence int32) (codersd
135
137
return validKey (key ,now )
136
138
}
137
139
140
+ // refresh fetches the keys from the control plane and updates the cache.
138
141
func (k * CryptoKeyCache )refresh () {
139
142
if k .isClosed () {
140
143
return
141
144
}
142
145
146
+ now := k .Clock .Now ("CryptoKeyCache" ,"refresh" )
143
147
k .fetchLock .Lock ()
144
148
defer k .fetchLock .Unlock ()
145
149
@@ -154,7 +158,7 @@ func (k *CryptoKeyCache) refresh() {
154
158
// There's a window we must account for where the timer fires while a fetch
155
159
// is ongoing but prior to the timer getting reset. In this case we want to
156
160
// avoid double fetching.
157
- if k . Clock . Now () .Sub (lastFetch )< time .Minute * 10 {
161
+ if now .Sub (lastFetch )< time .Minute * 10 {
158
162
return
159
163
}
160
164
@@ -165,7 +169,9 @@ func (k *CryptoKeyCache) refresh() {
165
169
}
166
170
}
167
171
168
- func (k * CryptoKeyCache )fetchKeys (ctx context.Context ) (map [int32 ]codersdk.CryptoKey , codersdk.CryptoKey ,error ) {
172
+ // cryptoKeys queries the control plane for the crypto keys.
173
+ // Outside of initialization, this should only be called by fetch.
174
+ func (k * CryptoKeyCache )cryptoKeys (ctx context.Context ) (map [int32 ]codersdk.CryptoKey , codersdk.CryptoKey ,error ) {
169
175
keys ,err := k .client .CryptoKeys (ctx )
170
176
if err != nil {
171
177
return nil , codersdk.CryptoKey {},xerrors .Errorf ("crypto keys: %w" ,err )
@@ -176,8 +182,9 @@ func (k *CryptoKeyCache) fetchKeys(ctx context.Context) (map[int32]codersdk.Cryp
176
182
177
183
// fetch fetches the keys from the control plane and updates the cache. The fetchMu
178
184
// must be held when calling this function to avoid multiple concurrent fetches.
185
+ // The returned keys are safe to use without additional locking.
179
186
func (k * CryptoKeyCache )fetch (ctx context.Context ) (map [int32 ]codersdk.CryptoKey , codersdk.CryptoKey ,error ) {
180
- keys ,latest ,err := k .fetchKeys (ctx )
187
+ keys ,latest ,err := k .cryptoKeys (ctx )
181
188
if err != nil {
182
189
return nil , codersdk.CryptoKey {},xerrors .Errorf ("fetch keys: %w" ,err )
183
190
}
@@ -196,7 +203,7 @@ func (k *CryptoKeyCache) fetch(ctx context.Context) (map[int32]codersdk.CryptoKe
196
203
197
204
k .lastFetch = k .Clock .Now ()
198
205
k .refresher .Reset (time .Minute * 10 )
199
- k .keys ,k .latest = keys ,latest
206
+ k .keys ,k .latest = maps . Clone ( keys ) ,latest
200
207
201
208
return keys ,latest ,nil
202
209
}
@@ -226,8 +233,8 @@ func (k *CryptoKeyCache) isClosed() bool {
226
233
}
227
234
228
235
func (k * CryptoKeyCache )Close () {
229
- //The fetch lock must always be held before holding the keys lock
230
- //otherwise we risk a deadlock .
236
+ //It's important to hold the locks here so that we don't unintentionally
237
+ //reset the timer via an in flight request when Close is called .
231
238
k .fetchLock .Lock ()
232
239
defer k .fetchLock .Unlock ()
233
240
@@ -239,5 +246,6 @@ func (k *CryptoKeyCache) Close() {
239
246
}
240
247
241
248
k .refreshCancel ()
249
+ k .refresher .Stop ()
242
250
k .closed .Store (true )
243
251
}