@@ -22,33 +22,53 @@ import (
22
22
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
23
23
"github.com/theupdateframework/go-tuf"
24
24
"github.com/urfave/cli/v2"
25
- "golang.org/x/crypto/ssh/terminal "
25
+ "golang.org/x/term "
26
26
)
27
27
28
28
const (
29
29
// consistentSnapshots are not needed due to the low update frequency of
30
30
// these repositories.
31
31
consistentSnapshots = false
32
32
33
- // ~10 years
34
- keyExpirationDuration = 10 * 365 * 24 * time .Hour
35
-
36
- // Expirations from
37
- // https://github.com/theupdateframework/notary/blob/e87b31f46cdc5041403c64b7536df236d5e35860/docs/best_practices.md#expiration-prevention
38
- // ~10 years
39
- rootExpirationDuration = 10 * 365 * 24 * time .Hour //nolint:unused,deadcode
40
- // ~3 years
41
- targetsExpirationDuration = 3 * 365 * 24 * time .Hour
42
- // ~3 years
43
- snapshotExpirationDuration = 3 * 365 * 24 * time .Hour
44
- // 14 days
45
- timestampExpirationDuration = 14 * 24 * time .Hour
46
-
47
33
decryptionFailedError = "encrypted: decryption failed"
48
34
49
35
backupDirectory = ".backup"
50
36
)
51
37
38
+ // The following are defined as string variables so that we can use/set them in tests and test tooling.
39
+ var (
40
+ // keyExpirationDuration is used when generating new keys (repository init)
41
+ // or when rotating the root key.
42
+ // ~10 years (10 * 365 * 24 hours)
43
+ keyExpirationDuration = "87600h"
44
+
45
+ //
46
+ // Expirations from
47
+ // https://github.com/theupdateframework/notary/blob/e87b31f46cdc5041403c64b7536df236d5e35860/docs/best_practices.md#expiration-prevention
48
+ //
49
+ // They are defined as string so we can modify them at build time for testing purposes.
50
+ //
51
+
52
+ // rootExpirationDuration is used to set the expiration of root.json when revoking the current root key.
53
+ // ~10 years (10 * 365 * 24 hours)
54
+ rootExpirationDuration = "87600h"
55
+ // targetsExpirationDuration is used to set the expiration of the targets.json signature.
56
+ // ~3 years (3 * 365 * 24 hours)
57
+ targetsExpirationDuration = "26280h"
58
+ // snapshotExpirationDuration is used to set the expiration of the snapshot.json signature.
59
+ // ~3 years (3 * 365 * 24 hours)
60
+ snapshotExpirationDuration = "26280h"
61
+ // timestampExpirationDuration is used to set the expiration of the timestamp.json signature.
62
+ // 14 days (14 * 24 hours)
63
+ timestampExpirationDuration = "336h"
64
+
65
+ keyExpirationDuration_ = mustParseDuration (keyExpirationDuration )
66
+ rootExpirationDuration_ = mustParseDuration (rootExpirationDuration )
67
+ targetsExpirationDuration_ = mustParseDuration (targetsExpirationDuration )
68
+ snapshotExpirationDuration_ = mustParseDuration (snapshotExpirationDuration )
69
+ timestampExpirationDuration_ = mustParseDuration (timestampExpirationDuration )
70
+ )
71
+
52
72
var passHandler = newPassphraseHandler ()
53
73
54
74
func UpdatesCommand () * cli.Command {
@@ -87,6 +107,14 @@ func updatesInitCommand() *cli.Command {
87
107
}
88
108
}
89
109
110
+ func mustParseDuration (s string ) time.Duration {
111
+ d , err := time .ParseDuration (s )
112
+ if err != nil {
113
+ panic (err )
114
+ }
115
+ return d
116
+ }
117
+
90
118
func updatesInitFunc (c * cli.Context ) error {
91
119
path := c .String ("path" )
92
120
store := tuf .FileSystemStore (path , passHandler .getPassphrase )
@@ -134,14 +162,14 @@ func updatesInitFunc(c *cli.Context) error {
134
162
if err := repo .AddTargetsWithExpires (
135
163
nil ,
136
164
nil ,
137
- time .Now ().Add (targetsExpirationDuration ),
165
+ time .Now ().Add (targetsExpirationDuration_ ),
138
166
); err != nil {
139
167
return fmt .Errorf ("initialize targets: %w" , err )
140
168
}
141
- if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration )); err != nil {
169
+ if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration_ )); err != nil {
142
170
return fmt .Errorf ("make snapshot: %w" , err )
143
171
}
144
- if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration )); err != nil {
172
+ if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration_ )); err != nil {
145
173
return fmt .Errorf ("make timestamp: %w" , err )
146
174
}
147
175
@@ -256,10 +284,10 @@ func updatesAddFunc(c *cli.Context) error {
256
284
dstPath = filepath .Join (name , platform , tag , name )
257
285
}
258
286
switch {
259
- case name == "desktop" && platform == "windows" :
287
+ case name == constant . DesktopTUFTargetName && platform == "windows" :
260
288
// This is a special case for the desktop target on Windows.
261
289
dstPath = filepath .Join (filepath .Dir (dstPath ), constant .DesktopAppExecName + ".exe" )
262
- case name == "desktop" && (platform == "linux" || platform == "linux-arm64" ):
290
+ case name == constant . DesktopTUFTargetName && (platform == "linux" || platform == "linux-arm64" ):
263
291
// This is a special case for the desktop target on Linux.
264
292
dstPath += ".tar.gz"
265
293
// The convention for Windows extensions is to use the extension `.ext.exe`
@@ -294,16 +322,16 @@ func updatesAddFunc(c *cli.Context) error {
294
322
if err := repo .AddTargetsWithExpires (
295
323
paths ,
296
324
meta ,
297
- time .Now ().Add (targetsExpirationDuration ),
325
+ time .Now ().Add (targetsExpirationDuration_ ),
298
326
); err != nil {
299
327
return fmt .Errorf ("add targets: %w" , err )
300
328
}
301
329
302
- if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration )); err != nil {
330
+ if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration_ )); err != nil {
303
331
return fmt .Errorf ("make snapshot: %w" , err )
304
332
}
305
333
306
- if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration )); err != nil {
334
+ if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration_ )); err != nil {
307
335
return fmt .Errorf ("make timestamp: %w" , err )
308
336
}
309
337
@@ -336,7 +364,7 @@ func updatesTimestampFunc(c *cli.Context) error {
336
364
}
337
365
338
366
if err := repo .TimestampWithExpires (
339
- time .Now ().Add (timestampExpirationDuration ),
367
+ time .Now ().Add (timestampExpirationDuration_ ),
340
368
); err != nil {
341
369
return fmt .Errorf ("make timestamp: %w" , err )
342
370
}
@@ -415,7 +443,7 @@ func updatesRotateFunc(c *cli.Context) error {
415
443
// Delete old keys for role
416
444
for _ , key := range keys {
417
445
id := key .PublicData ().IDs ()[0 ]
418
- err := repo .RevokeKeyWithExpires (role , id , time .Now ().Add (rootExpirationDuration ))
446
+ err := repo .RevokeKeyWithExpires (role , id , time .Now ().Add (rootExpirationDuration_ ))
419
447
if err != nil {
420
448
// go-tuf keeps keys around even after they are revoked from the manifest. We can skip
421
449
// tuf.ErrKeyNotFound as these represent keys that are not present in the manifest and
@@ -441,15 +469,15 @@ func updatesRotateFunc(c *cli.Context) error {
441
469
442
470
// Generate new metadata for each role (technically some of these may not need regeneration
443
471
// depending on which key was rotated, but there should be no harm in generating new ones for each).
444
- if err := repo .AddTargetsWithExpires (nil , nil , time .Now ().Add (targetsExpirationDuration )); err != nil {
472
+ if err := repo .AddTargetsWithExpires (nil , nil , time .Now ().Add (targetsExpirationDuration_ )); err != nil {
445
473
return fmt .Errorf ("generate targets: %w" , err )
446
474
}
447
475
448
- if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration )); err != nil {
476
+ if err := repo .SnapshotWithExpires (time .Now ().Add (snapshotExpirationDuration_ )); err != nil {
449
477
return fmt .Errorf ("generate snapshot: %w" , err )
450
478
}
451
479
452
- if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration )); err != nil {
480
+ if err := repo .TimestampWithExpires (time .Now ().Add (timestampExpirationDuration_ )); err != nil {
453
481
return fmt .Errorf ("generate timestamp: %w" , err )
454
482
}
455
483
@@ -619,7 +647,7 @@ func copyTarget(srcPath, dstPath string) error {
619
647
}
620
648
621
649
func updatesGenKey (repo * tuf.Repo , role string ) error {
622
- keyids , err := repo .GenKeyWithExpires (role , time .Now ().Add (keyExpirationDuration ))
650
+ keyids , err := repo .GenKeyWithExpires (role , time .Now ().Add (keyExpirationDuration_ ))
623
651
if err != nil {
624
652
return fmt .Errorf ("generate %s key: %w" , role , err )
625
653
}
@@ -715,7 +743,7 @@ func (p *passphraseHandler) readPassphrase(role string, confirm bool) ([]byte, e
715
743
716
744
fmt .Printf ("Enter %s key passphrase: " , role )
717
745
// the int(...) conversion is required as on Windows syscall.Stdin is of type Handle.
718
- passphrase , err := terminal .ReadPassword (int (syscall .Stdin )) //nolint:unconvert
746
+ passphrase , err := term .ReadPassword (int (syscall .Stdin )) //nolint:unconvert
719
747
fmt .Println ()
720
748
if err != nil {
721
749
return nil , fmt .Errorf ("read password: %w" , err )
@@ -727,7 +755,7 @@ func (p *passphraseHandler) readPassphrase(role string, confirm bool) ([]byte, e
727
755
728
756
fmt .Printf ("Repeat %s key passphrase: " , role )
729
757
// the int(...) conversion is required as on Windows syscall.Stdin is of type Handle.
730
- confirmation , err := terminal .ReadPassword (int (syscall .Stdin )) //nolint:unconvert
758
+ confirmation , err := term .ReadPassword (int (syscall .Stdin )) //nolint:unconvert
731
759
fmt .Println ()
732
760
if err != nil {
733
761
return nil , fmt .Errorf ("read password confirmation: %w" , err )
0 commit comments