Add support for Chrome/Chromium on Linux

Fixes #11
Closes #15
This commit is contained in:
Filippo Valsorda 2018-07-03 22:26:37 -04:00
parent 02f776146c
commit ce54575308
5 changed files with 56 additions and 33 deletions

@ -37,7 +37,15 @@ brew install --HEAD https://github.com/FiloSottile/mkcert/raw/master/HomebrewFor
brew install nss # if you use Firefox 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 go get -u github.com/FiloSottile/mkcert

21
main.go

@ -79,9 +79,9 @@ func (m *mkcert) Run(args []string) {
warning = true warning = true
log.Println("Warning: the local CA is not installed in the system trust store! ⚠️") log.Println("Warning: the local CA is not installed in the system trust store! ⚠️")
} }
if hasFirefox && !m.checkFirefox() { if hasNSS && !m.checkNSS() {
warning = true 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 { if warning {
log.Println("Run \"mkcert -install\" to avoid verification errors ‼️") log.Println("Run \"mkcert -install\" to avoid verification errors ‼️")
@ -163,21 +163,20 @@ func (m *mkcert) install() {
var printed bool var printed bool
if !m.checkPlatform() { if !m.checkPlatform() {
m.installPlatform() 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" { if runtime.GOOS != "linux" {
log.Print("The local CA is now installed in the system trust store! ⚡️") log.Print("The local CA is now installed in the system trust store! ⚡️")
} }
printed = true printed = true
} }
if hasFirefox && !m.checkFirefox() { if hasNSS && !m.checkNSS() {
if hasCertutil { if hasCertutil {
m.installFirefox() m.installNSS()
log.Print("The local CA is now installed in the Firefox trust store (requires restart)! 🦊") log.Printf("The local CA is now installed in the %s trust store (requires browser restart)! 🦊", NSSBrowsers)
} else { } 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) log.Printf(`Install "certutil" with "%s" and re-run "mkcert -install" 👈`, CertutilInstallHelp)
} }
printed = true printed = true
@ -189,12 +188,12 @@ func (m *mkcert) install() {
func (m *mkcert) uninstall() { func (m *mkcert) uninstall() {
m.uninstallPlatform() m.uninstallPlatform()
if hasFirefox { if hasNSS {
if hasCertutil { if hasCertutil {
m.uninstallFirefox() m.uninstallNSS()
} else { } else {
log.Print("") 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.Printf(`You can install "certutil" with "%s" and re-run "mkcert -uninstall" 👈`, CertutilInstallHelp)
log.Print("") log.Print("")
} }

@ -20,6 +20,7 @@ var (
FirefoxPath = "/Applications/Firefox.app" FirefoxPath = "/Applications/Firefox.app"
FirefoxProfile = os.Getenv("HOME") + "/Library/Application Support/Firefox/Profiles/*" FirefoxProfile = os.Getenv("HOME") + "/Library/Application Support/Firefox/Profiles/*"
CertutilInstallHelp = "brew install nss" CertutilInstallHelp = "brew install nss"
NSSBrowsers = "Firefox"
) )
// https://github.com/golang/go/issues/24652#issuecomment-399826583 // https://github.com/golang/go/issues/24652#issuecomment-399826583

@ -13,7 +13,8 @@ import (
var ( var (
FirefoxPath = "/usr/bin/firefox" FirefoxPath = "/usr/bin/firefox"
FirefoxProfile = os.Getenv("HOME") + "/.mozilla/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() { func (m *mkcert) installPlatform() {

@ -10,31 +10,42 @@ import (
) )
var ( var (
hasFirefox bool hasNSS bool
hasCertutil bool hasCertutil bool
certutilPath string certutilPath string
nssDB = filepath.Join(os.Getenv("HOME"), ".pki/nssdb")
) )
func init() { func init() {
_, err := os.Stat(FirefoxPath) _, err := os.Stat(FirefoxPath)
hasFirefox = !os.IsNotExist(err) hasNSS = !os.IsNotExist(err)
out, err := exec.Command("brew", "--prefix", "nss").Output() switch runtime.GOOS {
if err != nil { case "darwin":
return 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 { if !hasCertutil {
return false return false
} }
success := true 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() err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run()
if err != nil { if err != nil {
success = false success = false
@ -45,8 +56,8 @@ func (m *mkcert) checkFirefox() bool {
return success return success
} }
func (m *mkcert) installFirefox() { func (m *mkcert) installNSS() {
if m.forEachFirefoxProfile(func(profile string) { if m.forEachNSSProfile(func(profile string) {
cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName)) cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName))
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -57,16 +68,16 @@ func (m *mkcert) installFirefox() {
} }
fatalIfCmdErr(err, "certutil -A", out) fatalIfCmdErr(err, "certutil -A", out)
}) == 0 { }) == 0 {
log.Println("ERROR: no Firefox security databases found") log.Printf("ERROR: no %s security databases found", NSSBrowsers)
} }
if !m.checkFirefox() { if !m.checkNSS() {
log.Println("Installing in Firefox failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎") 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.Println("Note that if you never started Firefox, you need to do that at least once.") log.Printf("Note that if you never started %s, you need to do that at least once.", NSSBrowsers)
} }
} }
func (m *mkcert) uninstallFirefox() { func (m *mkcert) uninstallNSS() {
m.forEachFirefoxProfile(func(profile string) { m.forEachNSSProfile(func(profile string) {
err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run() err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run()
if err != nil { if err != nil {
return 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) profiles, _ := filepath.Glob(FirefoxProfile)
if _, err := os.Stat(nssDB); !os.IsNotExist(err) {
profiles = append(profiles, nssDB)
}
if len(profiles) == 0 { if len(profiles) == 0 {
return return
} }