command/token: helper to read/write tokens from a helper
This commit is contained in:
parent
e78c972351
commit
62e36ecb68
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue