Skip to content

Commit 1652da2

Browse files
feat: mkcert shell-out with cache reuse
1 parent 7228aad commit 1652da2

1 file changed

Lines changed: 34 additions & 0 deletions

File tree

cert.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package main
22

33
import (
4+
"errors"
5+
"fmt"
46
"os"
7+
"os/exec"
58
"path/filepath"
69
"time"
710
)
@@ -28,3 +31,34 @@ func shouldRegenerate(certPath, keyPath string, maxAge time.Duration) bool {
2831
cutoff := time.Now().Add(-maxAge)
2932
return certInfo.ModTime().Before(cutoff) || keyInfo.ModTime().Before(cutoff)
3033
}
34+
35+
// ensureCert returns paths to a valid cached cert+key, regenerating via mkcert if needed.
36+
// extraHosts is added to the mkcert SAN list in addition to localhost, 127.0.0.1, ::1.
37+
func ensureCert(extraHosts []string) (certPath, keyPath string, err error) {
38+
dir := certCacheDir()
39+
if err := os.MkdirAll(dir, 0o700); err != nil {
40+
return "", "", fmt.Errorf("create cert cache dir: %w", err)
41+
}
42+
certPath = filepath.Join(dir, "localhost.pem")
43+
keyPath = filepath.Join(dir, "localhost.key")
44+
45+
if !shouldRegenerate(certPath, keyPath, 30*24*time.Hour) {
46+
return certPath, keyPath, nil
47+
}
48+
49+
if _, err := exec.LookPath("mkcert"); err != nil {
50+
return "", "", errors.New(
51+
"mkcert not found on PATH.\n" +
52+
"install it first:\n" +
53+
" brew install mkcert && mkcert -install",
54+
)
55+
}
56+
57+
hosts := append([]string{"localhost", "127.0.0.1", "::1"}, extraHosts...)
58+
args := append([]string{"-cert-file", certPath, "-key-file", keyPath}, hosts...)
59+
cmd := exec.Command("mkcert", args...)
60+
if out, err := cmd.CombinedOutput(); err != nil {
61+
return "", "", fmt.Errorf("mkcert failed: %w\n%s", err, string(out))
62+
}
63+
return certPath, keyPath, nil
64+
}

0 commit comments

Comments
 (0)