Skip to content

Commit

Permalink
add support for any external command as "cmd:command goes here"
Browse files Browse the repository at this point in the history
  • Loading branch information
jschauma committed May 29, 2022
1 parent 4103bea commit 074a6e5
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ The `getpass` module provides a simple way to retrieve a password from
the user by specifying a number of different password sources:

```
func Getpass(passfrom) (pass string, err error)
func Getpass(passfrom string) (pass string, err error)
```

Getpass retrieves a password from the user using a method defined by
the `passfrom` string. The following methods are supported:

`cmd:command` -- Obtain the password by running the given command. The
command will be passed to the shell for execution via "/bin/sh -c
'command'".

`env:var` -- Obtain the password from the environment variable var.
Since the environment of other processes may be visible
via e.g. ps(1), this option should be used with caution.
Expand Down Expand Up @@ -78,7 +82,7 @@ func main() {
}
// Using a custom prompt:
p, err = getpass.Getpass("tty:Please enter your secret passphrase: ")
p, err = getpass.Getpass("tty", "Please enter your secret passphrase: ")
if err != nil {
log.Fatal("Unable to get password from user: %v\n", err)
} else {
Expand Down
7 changes: 7 additions & 0 deletions example/getpass_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,12 @@ func main() {
fmt.Printf("%s\n", p)
}

// Using a command:
p, err = getpass.Getpass("cmd:env | grep -i mysecret")
if err != nil {
log.Fatal("Unable to get password from user: ", err)
} else {
fmt.Printf("%s\n", p)
}
// etc. etc.
}
22 changes: 18 additions & 4 deletions getpass.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ import (
"fmt"
"os"
"os/exec"
"os/user"
"os/signal"
"os/user"
"regexp"
"runtime"
"strings"
"syscall"
)

// Getpass retrieves a password from the user using a
// method defined by the 'passfrom' string. The
// following methods are supported:
// Getpass retrieves a password from the user using a method defined by
// the 'passfrom' string. The following methods are supported:
//
// cmd:command Obtain the password by running the given command.
// The command will be passed to the shell for execution
// via "/bin/sh -c 'command'".
//
// env:var Obtain the password from the environment variable var.
// Since the environment of other processes may be visible
Expand Down Expand Up @@ -77,6 +80,8 @@ func Getpass(passfrom ...string) (pass string, err error) {
}

switch source {
case "cmd":
return getpassFromCommand(passin[1])
case "env":
return getpassFromEnv(passin[1])
case "file":
Expand Down Expand Up @@ -105,6 +110,15 @@ func Getpass(passfrom ...string) (pass string, err error) {
return pass, nil
}

func getpassFromCommand(command string) (pass string, err error) {
cmd := []string{"/bin/sh", "-c", command}
out, err := runCommand(cmd, "", true)
if err != nil {
return "", err
}
return out, nil
}

func getpassFromEnv(varname string) (pass string, err error) {
errMsg := fmt.Sprintf("environment variable '%v' not set", varname)
pass = os.Getenv(varname)
Expand Down
18 changes: 18 additions & 0 deletions getpass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ func TestGetpassPass(t *testing.T) {
}
}

// TestGetpassPass tests that Getpass with a passfrom set to 'cmd:'
// executes the given command with full shell evaluation..
func TestGetpassCmd(t *testing.T) {
want := os.Getenv("PATH")
cmd := "echo $PATH"
p, err := Getpass("cmd:" + cmd)
if err != nil || p != want {
t.Fatalf(`Getpass("cmd:%s") = %q, %v, want %s, nil`, cmd, p, err, want)
}

want = "/dev/null"
cmd = "ls -l /dev/null | awk '{print $NF}'"
p, err = Getpass("cmd:" + cmd)
if err != nil || p != want {
t.Fatalf(`Getpass("cmd:%s") = %q, %v, want %s, nil`, cmd, p, err, want)
}
}

// TestGetpassFail tests that Getpass with an invalid
// passfrom fails.
func TestGetpassFail(t *testing.T) {
Expand Down

0 comments on commit 074a6e5

Please sign in to comment.