Derive from the mnemonic's words joined by single spaces (closes #49) #53

Merged
clawbot merged 1 commits from issue-49-mnemonic-single-spaces into next 2026-10-04 07:08:47 +02:00
3 changed files with 28 additions and 7 deletions
Showing only changes of commit f5f317eb66 - Show all commits
+5 -4
View File
@@ -106,9 +106,8 @@ order; the first one found wins:
1. `--mnemonic-command <command>`: a shell command, run with `sh -c`, whose 1. `--mnemonic-command <command>`: a shell command, run with `sh -c`, whose
standard output is the mnemonic. Example: standard output is the mnemonic. Example:
`--mnemonic-command 'secret get foo'`. Whitespace around the output is `--mnemonic-command 'secret get foo'`. If the command exits with a non-zero
dropped. If the command exits with a non-zero status, the tool prints its status, the tool prints its standard error and exits with status 1.
standard error and exits with status 1.
2. Environment variable `KEYFUNC_MNEMONIC_COMMAND`: the same, as a shell command 2. Environment variable `KEYFUNC_MNEMONIC_COMMAND`: the same, as a shell command
held in the environment. held in the environment.
3. Environment variable `KEYFUNC_MNEMONIC`: the mnemonic itself. 3. Environment variable `KEYFUNC_MNEMONIC`: the mnemonic itself.
@@ -116,7 +115,9 @@ order; the first one found wins:
If none of these is available and standard input is not a terminal, the tool If none of these is available and standard input is not a terminal, the tool
refuses and exits with status 1. A mnemonic that fails the BIP-39 checksum is refuses and exits with status 1. A mnemonic that fails the BIP-39 checksum is
refused with a message saying so. refused with a message saying so. Keys are derived from the mnemonic's words
joined by single spaces, whatever whitespace is around or between them, so one
word per line, tabs or extra spaces give the same keys.
`KEYFUNC_MNEMONIC` and `KEYFUNC_MNEMONIC_COMMAND` are removed from the `KEYFUNC_MNEMONIC` and `KEYFUNC_MNEMONIC_COMMAND` are removed from the
environment before the system `ssh` (`keyfunc ssh to`) and `sftp` environment before the system `ssh` (`keyfunc ssh to`) and `sftp`
+19
View File
@@ -47,6 +47,25 @@ func TestTheReadmeTestVectors(t *testing.T) {
) )
} }
func TestTheSpacingBetweenTheWordsDoesNotChangeTheKeys(t *testing.T) {
words := strings.Fields(example())
for name, spaced := range map[string]string{
"one word per line": strings.Join(words, "\n"),
"double spaces": strings.Join(words, " "),
"tabs": strings.Join(words, "\t"),
} {
t.Run(name, func(t *testing.T) {
t.Setenv(mnemonic.Variable, spaced)
require.Equal(t,
vectorZero+" keyfunc/ssh/0",
strings.TrimSpace(run(t, "ssh", "pub", "-n", "0")),
)
})
}
}
func TestTheCommentCanBeChosen(t *testing.T) { func TestTheCommentCanBeChosen(t *testing.T) {
t.Setenv(mnemonic.Variable, example()) t.Setenv(mnemonic.Variable, example())
+4 -3
View File
@@ -104,10 +104,11 @@ func ask() (string, error) {
return checked(string(typed)) return checked(string(typed))
} }
// checked drops the surrounding whitespace and refuses a mnemonic that // checked joins the words with single spaces, whatever whitespace
// does not pass the BIP-39 checksum. // separated them, since the seed is computed over the string itself,
// and refuses a mnemonic that does not pass the BIP-39 checksum.
func checked(words string) (string, error) { func checked(words string) (string, error) {
words = strings.TrimSpace(words) words = strings.Join(strings.Fields(words), " ")
if !bip39.IsMnemonicValid(words) { if !bip39.IsMnemonicValid(words) {
return "", ErrChecksum return "", ErrChecksum