-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcert.go
More file actions
64 lines (57 loc) · 1.91 KB
/
Copy pathcert.go
File metadata and controls
64 lines (57 loc) · 1.91 KB
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
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"time"
)
// certCacheDir returns the directory where cached certs live.
// Follows XDG Base Directory spec.
func certCacheDir() string {
if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
return filepath.Join(xdg, "httpsdev", "certs")
}
return filepath.Join(os.Getenv("HOME"), ".config", "httpsdev", "certs")
}
// shouldRegenerate returns true if either cert file is missing or older than maxAge.
func shouldRegenerate(certPath, keyPath string, maxAge time.Duration) bool {
certInfo, err := os.Stat(certPath)
if err != nil {
return true
}
keyInfo, err := os.Stat(keyPath)
if err != nil {
return true
}
cutoff := time.Now().Add(-maxAge)
return certInfo.ModTime().Before(cutoff) || keyInfo.ModTime().Before(cutoff)
}
// ensureCert returns paths to a valid cached cert+key, regenerating via mkcert if needed.
// extraHosts is added to the mkcert SAN list in addition to localhost, 127.0.0.1, ::1.
func ensureCert(extraHosts []string) (certPath, keyPath string, err error) {
dir := certCacheDir()
if err := os.MkdirAll(dir, 0o700); err != nil {
return "", "", fmt.Errorf("create cert cache dir: %w", err)
}
certPath = filepath.Join(dir, "localhost.pem")
keyPath = filepath.Join(dir, "localhost.key")
if !shouldRegenerate(certPath, keyPath, 30*24*time.Hour) {
return certPath, keyPath, nil
}
if _, err := exec.LookPath("mkcert"); err != nil {
return "", "", errors.New(
"mkcert not found on PATH.\n" +
"install it first:\n" +
" brew install mkcert && mkcert -install",
)
}
hosts := append([]string{"localhost", "127.0.0.1", "::1"}, extraHosts...)
args := append([]string{"-cert-file", certPath, "-key-file", keyPath}, hosts...)
cmd := exec.Command("mkcert", args...)
if out, err := cmd.CombinedOutput(); err != nil {
return "", "", fmt.Errorf("mkcert failed: %w\n%s", err, string(out))
}
return certPath, keyPath, nil
}