Просмотр исходного кода

Specify a "Sudo password:" prompt for sudo

Fixes #178
Closes #185
Filippo Valsorda 5 лет назад
Родитель
Сommit
aa4dd61066
4 измененных файлов с 28 добавлено и 20 удалено
  1. 17 0
      main.go
  2. 4 5
      truststore_darwin.go
  3. 2 2
      truststore_java.go
  4. 5 13
      truststore_linux.go

+ 17 - 0
main.go

@@ -16,10 +16,12 @@ import (
 	"net/url"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
 	"regexp"
 	"runtime"
 	"strings"
+	"sync"
 
 	"golang.org/x/net/idna"
 )
@@ -345,3 +347,18 @@ func binaryExists(name string) bool {
 	_, err := exec.LookPath(name)
 	return err == nil
 }
+
+var sudoWarningOnce sync.Once
+
+func commandWithSudo(cmd ...string) *exec.Cmd {
+	if u, err := user.Current(); err == nil && u.Uid == "0" {
+		return exec.Command(cmd[0], cmd[1:]...)
+	}
+	if !binaryExists("sudo") {
+		sudoWarningOnce.Do(func() {
+			log.Println(`Warning: "sudo" is not available, and mkcert is not running as root. The (un)install operation might fail. ⚠️`)
+		})
+		return exec.Command(cmd[0], cmd[1:]...)
+	}
+	return exec.Command("sudo", append([]string{"--prompt=Sudo password:", "--"}, cmd...)...)
+}

+ 4 - 5
truststore_darwin.go

@@ -10,7 +10,6 @@ import (
 	"io/ioutil"
 	"log"
 	"os"
-	"os/exec"
 	"path/filepath"
 
 	"howett.net/plist"
@@ -51,7 +50,7 @@ var trustSettingsData = []byte(`
 `)
 
 func (m *mkcert) installPlatform() bool {
-	cmd := exec.Command("sudo", "security", "add-trusted-cert", "-d", "-k", "/Library/Keychains/System.keychain", filepath.Join(m.CAROOT, rootName))
+	cmd := commandWithSudo("security", "add-trusted-cert", "-d", "-k", "/Library/Keychains/System.keychain", filepath.Join(m.CAROOT, rootName))
 	out, err := cmd.CombinedOutput()
 	fatalIfCmdErr(err, "security add-trusted-cert", out)
 
@@ -62,7 +61,7 @@ func (m *mkcert) installPlatform() bool {
 	fatalIfErr(err, "failed to create temp file")
 	defer os.Remove(plistFile.Name())
 
-	cmd = exec.Command("sudo", "security", "trust-settings-export", "-d", plistFile.Name())
+	cmd = commandWithSudo("security", "trust-settings-export", "-d", plistFile.Name())
 	out, err = cmd.CombinedOutput()
 	fatalIfCmdErr(err, "security trust-settings-export", out)
 
@@ -96,7 +95,7 @@ func (m *mkcert) installPlatform() bool {
 	err = ioutil.WriteFile(plistFile.Name(), plistData, 0600)
 	fatalIfErr(err, "failed to write trust settings")
 
-	cmd = exec.Command("sudo", "security", "trust-settings-import", "-d", plistFile.Name())
+	cmd = commandWithSudo("security", "trust-settings-import", "-d", plistFile.Name())
 	out, err = cmd.CombinedOutput()
 	fatalIfCmdErr(err, "security trust-settings-import", out)
 
@@ -104,7 +103,7 @@ func (m *mkcert) installPlatform() bool {
 }
 
 func (m *mkcert) uninstallPlatform() bool {
-	cmd := exec.Command("sudo", "security", "remove-trusted-cert", "-d", filepath.Join(m.CAROOT, rootName))
+	cmd := commandWithSudo("security", "remove-trusted-cert", "-d", filepath.Join(m.CAROOT, rootName))
 	out, err := cmd.CombinedOutput()
 	fatalIfCmdErr(err, "security remove-trusted-cert", out)
 

+ 2 - 2
truststore_java.go

@@ -106,12 +106,12 @@ func (m *mkcert) uninstallJava() {
 }
 
 // execKeytool will execute a "keytool" command and if needed re-execute
-// the command wrapped in 'sudo' to work around file permissions.
+// the command with commandWithSudo to work around file permissions.
 func (m *mkcert) execKeytool(cmd *exec.Cmd) ([]byte, error) {
 	out, err := cmd.CombinedOutput()
 	if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) && runtime.GOOS != "windows" {
 		origArgs := cmd.Args[1:]
-		cmd = exec.Command("sudo", keytoolPath)
+		cmd = commandWithSudo(keytoolPath)
 		cmd.Args = append(cmd.Args, origArgs...)
 		cmd.Env = []string{
 			"JAVA_HOME=" + javaHome,

+ 5 - 13
truststore_linux.go

@@ -10,7 +10,6 @@ import (
 	"io/ioutil"
 	"log"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"strings"
 )
@@ -65,12 +64,12 @@ func (m *mkcert) installPlatform() bool {
 	cert, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootName))
 	fatalIfErr(err, "failed to read root certificate")
 
-	cmd := CommandWithSudo("tee", m.systemTrustFilename())
+	cmd := commandWithSudo("tee", m.systemTrustFilename())
 	cmd.Stdin = bytes.NewReader(cert)
 	out, err := cmd.CombinedOutput()
 	fatalIfCmdErr(err, "tee", out)
 
-	cmd = CommandWithSudo(SystemTrustCommand...)
+	cmd = commandWithSudo(SystemTrustCommand...)
 	out, err = cmd.CombinedOutput()
 	fatalIfCmdErr(err, strings.Join(SystemTrustCommand, " "), out)
 
@@ -82,28 +81,21 @@ func (m *mkcert) uninstallPlatform() bool {
 		return false
 	}
 
-	cmd := CommandWithSudo("rm", "-f", m.systemTrustFilename())
+	cmd := commandWithSudo("rm", "-f", m.systemTrustFilename())
 	out, err := cmd.CombinedOutput()
 	fatalIfCmdErr(err, "rm", out)
 
 	// We used to install under non-unique filenames.
 	legacyFilename := fmt.Sprintf(SystemTrustFilename, "mkcert-rootCA")
 	if pathExists(legacyFilename) {
-		cmd := CommandWithSudo("rm", "-f", legacyFilename)
+		cmd := commandWithSudo("rm", "-f", legacyFilename)
 		out, err := cmd.CombinedOutput()
 		fatalIfCmdErr(err, "rm (legacy filename)", out)
 	}
 
-	cmd = CommandWithSudo(SystemTrustCommand...)
+	cmd = commandWithSudo(SystemTrustCommand...)
 	out, err = cmd.CombinedOutput()
 	fatalIfCmdErr(err, strings.Join(SystemTrustCommand, " "), out)
 
 	return true
 }
-
-func CommandWithSudo(cmd ...string) *exec.Cmd {
-	if !binaryExists("sudo") {
-		return exec.Command(cmd[0], cmd[1:]...)
-	}
-	return exec.Command("sudo", append([]string{"--"}, cmd...)...)
-}