
Latest version of Firefox Developer Edition on macOS seem to use upper camel case naming for the app. This ensures that the CA will be added to the Firefox trust store if using recent versions of FF Dev Edition.
147 lines
4.0 KiB
Go
147 lines
4.0 KiB
Go
// Copyright 2018 The mkcert Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
hasNSS bool
|
|
hasCertutil bool
|
|
certutilPath string
|
|
nssDBs = []string{
|
|
filepath.Join(os.Getenv("HOME"), ".pki/nssdb"),
|
|
filepath.Join(os.Getenv("HOME"), "snap/chromium/current/.pki/nssdb"), // Snapcraft
|
|
"/etc/pki/nssdb", // CentOS 7
|
|
}
|
|
firefoxPaths = []string{
|
|
"/usr/bin/firefox",
|
|
"/usr/bin/firefox-nightly",
|
|
"/usr/bin/firefox-developer-edition",
|
|
"/Applications/Firefox.app",
|
|
"/Applications/FirefoxDeveloperEdition.app",
|
|
"/Applications/Firefox Developer Edition.app",
|
|
"/Applications/Firefox Nightly.app",
|
|
"C:\\Program Files\\Mozilla Firefox",
|
|
}
|
|
)
|
|
|
|
func init() {
|
|
allPaths := append(append([]string{}, nssDBs...), firefoxPaths...)
|
|
for _, path := range allPaths {
|
|
if pathExists(path) {
|
|
hasNSS = true
|
|
break
|
|
}
|
|
}
|
|
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
switch {
|
|
case binaryExists("certutil"):
|
|
certutilPath, _ = exec.LookPath("certutil")
|
|
hasCertutil = true
|
|
case binaryExists("/usr/local/opt/nss/bin/certutil"):
|
|
// Check the default Homebrew path, to save executing Ruby. #135
|
|
certutilPath = "/usr/local/opt/nss/bin/certutil"
|
|
hasCertutil = true
|
|
default:
|
|
out, err := exec.Command("brew", "--prefix", "nss").Output()
|
|
if err == nil {
|
|
certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil")
|
|
hasCertutil = pathExists(certutilPath)
|
|
}
|
|
}
|
|
|
|
case "linux":
|
|
if hasCertutil = binaryExists("certutil"); hasCertutil {
|
|
certutilPath, _ = exec.LookPath("certutil")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *mkcert) checkNSS() bool {
|
|
if !hasCertutil {
|
|
return false
|
|
}
|
|
success := true
|
|
if m.forEachNSSProfile(func(profile string) {
|
|
err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run()
|
|
if err != nil {
|
|
success = false
|
|
}
|
|
}) == 0 {
|
|
success = false
|
|
}
|
|
return success
|
|
}
|
|
|
|
func (m *mkcert) installNSS() bool {
|
|
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 := execCertutil(cmd)
|
|
fatalIfCmdErr(err, "certutil -A -d "+profile, out)
|
|
}) == 0 {
|
|
log.Printf("ERROR: no %s security databases found", NSSBrowsers)
|
|
return false
|
|
}
|
|
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)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
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
|
|
}
|
|
cmd := exec.Command(certutilPath, "-D", "-d", profile, "-n", m.caUniqueName())
|
|
out, err := execCertutil(cmd)
|
|
fatalIfCmdErr(err, "certutil -D -d "+profile, out)
|
|
})
|
|
}
|
|
|
|
// execCertutil will execute a "certutil" command and if needed re-execute
|
|
// the command with commandWithSudo to work around file permissions.
|
|
func execCertutil(cmd *exec.Cmd) ([]byte, error) {
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil && bytes.Contains(out, []byte("SEC_ERROR_READ_ONLY")) && runtime.GOOS != "windows" {
|
|
origArgs := cmd.Args[1:]
|
|
cmd = commandWithSudo(cmd.Path)
|
|
cmd.Args = append(cmd.Args, origArgs...)
|
|
out, err = cmd.CombinedOutput()
|
|
}
|
|
return out, err
|
|
}
|
|
|
|
func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) {
|
|
profiles, _ := filepath.Glob(FirefoxProfile)
|
|
profiles = append(profiles, nssDBs...)
|
|
for _, profile := range profiles {
|
|
if stat, err := os.Stat(profile); err != nil || !stat.IsDir() {
|
|
continue
|
|
}
|
|
if pathExists(filepath.Join(profile, "cert9.db")) {
|
|
f("sql:" + profile)
|
|
found++
|
|
} else if pathExists(filepath.Join(profile, "cert8.db")) {
|
|
f("dbm:" + profile)
|
|
found++
|
|
}
|
|
}
|
|
return
|
|
}
|