diff --git a/README.md b/README.md index c0e649c..3bb29a8 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,15 @@ brew install --HEAD https://github.com/FiloSottile/mkcert/raw/master/HomebrewFor brew install nss # if you use Firefox ``` -On Linux (`-install` support coming soon!), use [the pre-built binaries (again, coming soon)](https://github.com/FiloSottile/mkcert/releases), or build from source (requires Go 1.10+). +On Linux, install `certutil` + +``` +sudo apt install libnss3-tools + -or- +sudo yum install nss-tools +``` + +and build from source (requires Go 1.10+), or use [the pre-built binaries (coming soon)](https://github.com/FiloSottile/mkcert/releases). ``` go get -u github.com/FiloSottile/mkcert diff --git a/main.go b/main.go index f7f1b59..f1e3192 100644 --- a/main.go +++ b/main.go @@ -79,9 +79,9 @@ func (m *mkcert) Run(args []string) { warning = true log.Println("Warning: the local CA is not installed in the system trust store! ⚠️") } - if hasFirefox && !m.checkFirefox() { + if hasNSS && !m.checkNSS() { warning = true - log.Println("Warning: the local CA is not installed in the Firefox trust store! ⚠️") + log.Printf("Warning: the local CA is not installed in the %s trust store! ⚠️", NSSBrowsers) } if warning { log.Println("Run \"mkcert -install\" to avoid verification errors ‼️") @@ -163,21 +163,20 @@ func (m *mkcert) install() { var printed bool if !m.checkPlatform() { m.installPlatform() + m.ignoreCheckFailure = true // TODO: replace with a check for a successful install - // TODO: replace with a check for a successful install, drop OS check - m.ignoreCheckFailure = true if runtime.GOOS != "linux" { log.Print("The local CA is now installed in the system trust store! ⚡️") } printed = true } - if hasFirefox && !m.checkFirefox() { + if hasNSS && !m.checkNSS() { if hasCertutil { - m.installFirefox() - log.Print("The local CA is now installed in the Firefox trust store (requires restart)! 🦊") + m.installNSS() + log.Printf("The local CA is now installed in the %s trust store (requires browser restart)! 🦊", NSSBrowsers) } else { - log.Println(`Warning: "certutil" is not available, so the CA can't be automatically installed in Firefox! ⚠️`) + log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically installed in %s! ⚠️`, NSSBrowsers) log.Printf(`Install "certutil" with "%s" and re-run "mkcert -install" 👈`, CertutilInstallHelp) } printed = true @@ -189,12 +188,12 @@ func (m *mkcert) install() { func (m *mkcert) uninstall() { m.uninstallPlatform() - if hasFirefox { + if hasNSS { if hasCertutil { - m.uninstallFirefox() + m.uninstallNSS() } else { log.Print("") - log.Println(`Warning: "certutil" is not available, so the CA can't be automatically uninstalled from Firefox (if it was ever installed)! ⚠️`) + log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically uninstalled from %s (if it was ever installed)! ⚠️`, NSSBrowsers) log.Printf(`You can install "certutil" with "%s" and re-run "mkcert -uninstall" 👈`, CertutilInstallHelp) log.Print("") } diff --git a/truststore_darwin.go b/truststore_darwin.go index 3e38ca5..b78dba6 100644 --- a/truststore_darwin.go +++ b/truststore_darwin.go @@ -20,6 +20,7 @@ var ( FirefoxPath = "/Applications/Firefox.app" FirefoxProfile = os.Getenv("HOME") + "/Library/Application Support/Firefox/Profiles/*" CertutilInstallHelp = "brew install nss" + NSSBrowsers = "Firefox" ) // https://github.com/golang/go/issues/24652#issuecomment-399826583 diff --git a/truststore_linux.go b/truststore_linux.go index c488688..43f54c9 100644 --- a/truststore_linux.go +++ b/truststore_linux.go @@ -13,7 +13,8 @@ import ( var ( FirefoxPath = "/usr/bin/firefox" FirefoxProfile = os.Getenv("HOME") + "/.mozilla/firefox/*" - CertutilInstallHelp = "apt install libnss3-tools" + CertutilInstallHelp = `apt install libnss3-tools" or "yum install nss-tools` + NSSBrowsers = "Firefox and/or Chrome/Chromium" ) func (m *mkcert) installPlatform() { diff --git a/truststore_firefox.go b/truststore_nss.go similarity index 56% rename from truststore_firefox.go rename to truststore_nss.go index a0af97d..38e9ddc 100644 --- a/truststore_firefox.go +++ b/truststore_nss.go @@ -10,31 +10,42 @@ import ( ) var ( - hasFirefox bool + hasNSS bool hasCertutil bool certutilPath string + nssDB = filepath.Join(os.Getenv("HOME"), ".pki/nssdb") ) func init() { _, err := os.Stat(FirefoxPath) - hasFirefox = !os.IsNotExist(err) + hasNSS = !os.IsNotExist(err) - out, err := exec.Command("brew", "--prefix", "nss").Output() - if err != nil { - return + switch runtime.GOOS { + case "darwin": + out, err := exec.Command("brew", "--prefix", "nss").Output() + if err != nil { + return + } + certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil") + + _, err = os.Stat(certutilPath) + hasCertutil = !os.IsNotExist(err) + + case "linux": + _, err := os.Stat(nssDB) + hasNSS = hasNSS && !os.IsNotExist(err) + + certutilPath, err = exec.LookPath("certutil") + hasCertutil = err == nil } - certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil") - - _, err = os.Stat(certutilPath) - hasCertutil = !os.IsNotExist(err) } -func (m *mkcert) checkFirefox() bool { +func (m *mkcert) checkNSS() bool { if !hasCertutil { return false } success := true - if m.forEachFirefoxProfile(func(profile string) { + if m.forEachNSSProfile(func(profile string) { err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run() if err != nil { success = false @@ -45,8 +56,8 @@ func (m *mkcert) checkFirefox() bool { return success } -func (m *mkcert) installFirefox() { - if m.forEachFirefoxProfile(func(profile string) { +func (m *mkcert) installNSS() { + if m.forEachNSSProfile(func(profile string) { cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName)) out, err := cmd.CombinedOutput() if err != nil { @@ -57,16 +68,16 @@ func (m *mkcert) installFirefox() { } fatalIfCmdErr(err, "certutil -A", out) }) == 0 { - log.Println("ERROR: no Firefox security databases found") + log.Printf("ERROR: no %s security databases found", NSSBrowsers) } - if !m.checkFirefox() { - log.Println("Installing in Firefox failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎") - log.Println("Note that if you never started Firefox, you need to do that at least once.") + if !m.checkNSS() { + log.Printf("Installing in %s failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎", NSSBrowsers) + log.Printf("Note that if you never started %s, you need to do that at least once.", NSSBrowsers) } } -func (m *mkcert) uninstallFirefox() { - m.forEachFirefoxProfile(func(profile string) { +func (m *mkcert) uninstallNSS() { + m.forEachNSSProfile(func(profile string) { err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run() if err != nil { return @@ -77,8 +88,11 @@ func (m *mkcert) uninstallFirefox() { }) } -func (m *mkcert) forEachFirefoxProfile(f func(profile string)) (found int) { +func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) { profiles, _ := filepath.Glob(FirefoxProfile) + if _, err := os.Stat(nssDB); !os.IsNotExist(err) { + profiles = append(profiles, nssDB) + } if len(profiles) == 0 { return }