package cli_test import ( "bytes" "strings" "testing" "git.eeqj.de/sneak/keyfunc/internal/cli" "git.eeqj.de/sneak/keyfunc/internal/mnemonic" "github.com/stretchr/testify/require" "golang.org/x/crypto/ssh" ) // The two lines the README says the example mnemonic produces. const ( vectorZero = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZOtOczrc/7CQytc" + "uFwt7s4r8KjkZWkwjLZWBaFKD+7" vectorOne = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEWY8+/gmHYVC4u0Y" + "0I4FKs+eVUulTPHfk9VtXw1tMF" ) // example returns the mnemonic the README gives its test vectors for: // eleven abandons and about. func example() string { return strings.Repeat("abandon ", 11) + "about" } func TestTheReadmeTestVectors(t *testing.T) { t.Setenv(mnemonic.Variable, example()) require.Equal(t, vectorZero+" keyfunc/ssh/0", strings.TrimSpace(run(t, "ssh", "pub", "-n", "0")), ) require.Equal(t, vectorOne+" keyfunc/ssh/1", strings.TrimSpace(run(t, "ssh", "pub", "-n", "1")), ) } func TestTheCommentCanBeChosen(t *testing.T) { t.Setenv(mnemonic.Variable, example()) line := strings.TrimSpace(run(t, "ssh", "pub", "--comment", "mine")) require.Equal(t, vectorZero+" mine", line) } func TestThePrivateKeyMatchesThePublicOne(t *testing.T) { t.Setenv(mnemonic.Variable, example()) block := run(t, "ssh", "priv", "-n", "1") require.True(t, strings.HasPrefix(block, "-----BEGIN OPENSSH PRIVATE KEY-----"), ) parsed, err := ssh.ParsePrivateKey([]byte(block)) require.NoError(t, err) back := strings.TrimSpace( string(ssh.MarshalAuthorizedKey(parsed.PublicKey())), ) require.Equal(t, vectorOne, back) } func TestTheMnemonicCommandIsUsed(t *testing.T) { t.Setenv(mnemonic.Variable, "") line := strings.TrimSpace(run(t, "ssh", "pub", "--mnemonic-command", "printf '%s\\n' '"+example()+"'", )) require.Equal(t, vectorZero+" keyfunc/ssh/0", line) } // run executes the tool with the given arguments and returns what it // wrote to standard output. func run(t *testing.T, args ...string) string { t.Helper() var out bytes.Buffer root := cli.Root() root.SetOut(&out) root.SetErr(&out) root.SetArgs(args) require.NoError(t, root.ExecuteContext(t.Context())) return out.String() }