command/token: helper to read/write tokens from a helper

This commit is contained in:
Mitchell Hashimoto 2015-03-29 17:42:26 -07:00
parent e78c972351
commit 62e36ecb68
2 changed files with 169 additions and 0 deletions

53
command/token/helper.go Normal file
View File

@ -0,0 +1,53 @@
package token
import (
"bytes"
"os/exec"
)
// Helper is the struct that has all the logic for storing and retrieving
// tokens from the token helper. The API for the helpers is simple: the
// Path is executed within a shell. The last argument appended will be the
// operation, which is:
//
// * "get" - Read the value of the token and write it to stdout.
// * "store" - Store the value of the token which is on stdin. Output
// nothing.
// * "erase" - Erase the contents stored. Output nothing.
//
// Any errors can be written on stdout. If the helper exits with a non-zero
// exit code then the stderr will be made part of the error value.
type Helper struct {
Path string
}
// Erase deletes the contents from the helper.
func (h *Helper) Erase() error {
cmd := h.cmd("erase")
return cmd.Run()
}
// Get gets the token value from the helper.
func (h *Helper) Get() (string, error) {
var buf bytes.Buffer
cmd := h.cmd("get")
cmd.Stdout = &buf
if err := cmd.Run(); err != nil {
return "", err
}
return buf.String(), nil
}
// Store stores the token value into the helper.
func (h *Helper) Store(v string) error {
buf := bytes.NewBufferString(v)
cmd := h.cmd("store")
cmd.Stdin = buf
return cmd.Run()
}
func (h *Helper) cmd(op string) *exec.Cmd {
cmd := exec.Command("sh", "-c", h.Path+" "+op)
return cmd
}

View File

@ -0,0 +1,116 @@
package token
import (
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"testing"
)
func TestHelper(t *testing.T) {
h := testHelper(t)
if err := h.Store("foo"); err != nil {
t.Fatalf("err: %s", err)
}
v, err := h.Get()
if err != nil {
t.Fatalf("err: %s", err)
}
if v != "foo" {
t.Fatalf("bad: %#v", v)
}
if err := h.Erase(); err != nil {
t.Fatalf("err: %s", err)
}
v, err = h.Get()
if err != nil {
t.Fatalf("err: %s", err)
}
if v != "" {
t.Fatalf("bad: %#v", v)
}
}
func testHelper(t *testing.T) *Helper {
return &Helper{Path: helperPath("helper")}
}
func helperPath(s ...string) string {
tf, err := ioutil.TempFile("", "vault")
if err != nil {
panic(err)
}
tf.Close()
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
return fmt.Sprintf(
"GO_HELPER_PATH=%s GO_WANT_HELPER_PROCESS=1 %s %s",
tf.Name(),
os.Args[0],
strings.Join(cs, " "))
}
// This is not a real test. This is just a helper process kicked off by tests.
func TestHelperProcess(*testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
defer os.Exit(0)
args := os.Args
for len(args) > 0 {
if args[0] == "--" {
args = args[1:]
break
}
args = args[1:]
}
if len(args) == 0 {
fmt.Fprintf(os.Stderr, "No command\n")
os.Exit(2)
}
cmd, args := args[0], args[1:]
switch cmd {
case "helper":
path := os.Getenv("GO_HELPER_PATH")
switch args[0] {
case "erase":
os.Remove(path)
case "get":
f, err := os.Open(path)
if os.IsNotExist(err) {
return
}
if err != nil {
fmt.Fprintf(os.Stderr, "Err: %s\n", err)
os.Exit(1)
}
defer f.Close()
io.Copy(os.Stdout, f)
case "store":
f, err := os.Create(path)
if err != nil {
fmt.Fprintf(os.Stderr, "Err: %s\n", err)
os.Exit(1)
}
defer f.Close()
io.Copy(f, os.Stdin)
}
default:
fmt.Fprintf(os.Stderr, "Unknown command: %q\n", cmd)
os.Exit(2)
}
}