mirror of https://github.com/ethereum/go-ethereum
cmd/clef: add importraw feature to clef (#26058)
This adds a subcommand that imports a raw secp256k1 key into the keystore managed by clef.pull/26129/head
parent
33e23ee37d
commit
17744639da
@ -0,0 +1,117 @@ |
||||
// Copyright 2022 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
"testing" |
||||
) |
||||
|
||||
// TestImportRaw tests clef --importraw
|
||||
func TestImportRaw(t *testing.T) { |
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) |
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) |
||||
t.Cleanup(func() { os.Remove(keyPath) }) |
||||
|
||||
t.Parallel() |
||||
t.Run("happy-path", func(t *testing.T) { |
||||
// Run clef importraw
|
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) |
||||
clef.input("myverylongpassword").input("myverylongpassword") |
||||
if out := string(clef.Output()); !strings.Contains(out, |
||||
"Key imported:\n Address 0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6") { |
||||
t.Logf("Output\n%v", out) |
||||
t.Error("Failure") |
||||
} |
||||
}) |
||||
// tests clef --importraw with mismatched passwords.
|
||||
t.Run("pw-mismatch", func(t *testing.T) { |
||||
// Run clef importraw
|
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) |
||||
clef.input("myverylongpassword1").input("myverylongpassword2").WaitExit() |
||||
if have, want := clef.StderrText(), "Passwords do not match\n"; have != want { |
||||
t.Errorf("have %q, want %q", have, want) |
||||
} |
||||
}) |
||||
// tests clef --importraw with a too short password.
|
||||
t.Run("short-pw", func(t *testing.T) { |
||||
// Run clef importraw
|
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) |
||||
clef.input("shorty").input("shorty").WaitExit() |
||||
if have, want := clef.StderrText(), |
||||
"password requirements not met: password too short (<10 characters)\n"; have != want { |
||||
t.Errorf("have %q, want %q", have, want) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
// TestListAccounts tests clef --list-accounts
|
||||
func TestListAccounts(t *testing.T) { |
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) |
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) |
||||
t.Cleanup(func() { os.Remove(keyPath) }) |
||||
|
||||
t.Parallel() |
||||
t.Run("no-accounts", func(t *testing.T) { |
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-accounts") |
||||
if out := string(clef.Output()); !strings.Contains(out, "The keystore is empty.") { |
||||
t.Logf("Output\n%v", out) |
||||
t.Error("Failure") |
||||
} |
||||
}) |
||||
t.Run("one-account", func(t *testing.T) { |
||||
// First, we need to import
|
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) |
||||
clef.input("myverylongpassword").input("myverylongpassword").WaitExit() |
||||
// Secondly, do a listing, using the same datadir
|
||||
clef = runWithKeystore(t, clef.Datadir, "--suppress-bootwarn", "--lightkdf", "list-accounts") |
||||
if out := string(clef.Output()); !strings.Contains(out, "0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6 (keystore:") { |
||||
t.Logf("Output\n%v", out) |
||||
t.Error("Failure") |
||||
} |
||||
}) |
||||
} |
||||
|
||||
// TestListWallets tests clef --list-wallets
|
||||
func TestListWallets(t *testing.T) { |
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) |
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) |
||||
t.Cleanup(func() { os.Remove(keyPath) }) |
||||
|
||||
t.Parallel() |
||||
t.Run("no-accounts", func(t *testing.T) { |
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-wallets") |
||||
if out := string(clef.Output()); !strings.Contains(out, "There are no wallets.") { |
||||
t.Logf("Output\n%v", out) |
||||
t.Error("Failure") |
||||
} |
||||
}) |
||||
t.Run("one-account", func(t *testing.T) { |
||||
// First, we need to import
|
||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) |
||||
clef.input("myverylongpassword").input("myverylongpassword").WaitExit() |
||||
// Secondly, do a listing, using the same datadir
|
||||
clef = runWithKeystore(t, clef.Datadir, "--suppress-bootwarn", "--lightkdf", "list-wallets") |
||||
if out := string(clef.Output()); !strings.Contains(out, "Account 0: 0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6") { |
||||
t.Logf("Output\n%v", out) |
||||
t.Error("Failure") |
||||
} |
||||
}) |
||||
} |
@ -0,0 +1,109 @@ |
||||
// Copyright 2022 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"testing" |
||||
|
||||
"github.com/docker/docker/pkg/reexec" |
||||
"github.com/ethereum/go-ethereum/internal/cmdtest" |
||||
) |
||||
|
||||
const registeredName = "clef-test" |
||||
|
||||
type testproc struct { |
||||
*cmdtest.TestCmd |
||||
|
||||
// template variables for expect
|
||||
Datadir string |
||||
Etherbase string |
||||
} |
||||
|
||||
func init() { |
||||
reexec.Register(registeredName, func() { |
||||
if err := app.Run(os.Args); err != nil { |
||||
fmt.Fprintln(os.Stderr, err) |
||||
os.Exit(1) |
||||
} |
||||
os.Exit(0) |
||||
}) |
||||
} |
||||
|
||||
func TestMain(m *testing.M) { |
||||
// check if we have been reexec'd
|
||||
if reexec.Init() { |
||||
return |
||||
} |
||||
os.Exit(m.Run()) |
||||
} |
||||
|
||||
// runClef spawns clef with the given command line args and adds keystore arg.
|
||||
// This method creates a temporary keystore folder which will be removed after
|
||||
// the test exits.
|
||||
func runClef(t *testing.T, args ...string) *testproc { |
||||
ddir, err := os.MkdirTemp("", "cleftest-*") |
||||
if err != nil { |
||||
return nil |
||||
} |
||||
t.Cleanup(func() { |
||||
os.RemoveAll(ddir) |
||||
}) |
||||
return runWithKeystore(t, ddir, args...) |
||||
} |
||||
|
||||
// runWithKeystore spawns clef with the given command line args and adds keystore arg.
|
||||
// This method does _not_ create the keystore folder, but it _does_ add the arg
|
||||
// to the args.
|
||||
func runWithKeystore(t *testing.T, keystore string, args ...string) *testproc { |
||||
args = append([]string{"--keystore", keystore}, args...) |
||||
tt := &testproc{Datadir: keystore} |
||||
tt.TestCmd = cmdtest.NewTestCmd(t, tt) |
||||
// Boot "clef". This actually runs the test binary but the TestMain
|
||||
// function will prevent any tests from running.
|
||||
tt.Run(registeredName, args...) |
||||
return tt |
||||
} |
||||
|
||||
func (proc *testproc) input(text string) *testproc { |
||||
proc.TestCmd.InputLine(text) |
||||
return proc |
||||
} |
||||
|
||||
/* |
||||
// waitForEndpoint waits for the rpc endpoint to appear, or
|
||||
// aborts after 3 seconds.
|
||||
func (proc *testproc) waitForEndpoint(t *testing.T) *testproc { |
||||
t.Helper() |
||||
timeout := 3 * time.Second |
||||
ipc := filepath.Join(proc.Datadir, "clef.ipc") |
||||
|
||||
start := time.Now() |
||||
for time.Since(start) < timeout { |
||||
if _, err := os.Stat(ipc); !errors.Is(err, os.ErrNotExist) { |
||||
t.Logf("endpoint %v opened", ipc) |
||||
return proc |
||||
} |
||||
time.Sleep(200 * time.Millisecond) |
||||
} |
||||
t.Logf("stderr: \n%v", proc.StderrText()) |
||||
t.Logf("stdout: \n%v", proc.Output()) |
||||
t.Fatal("endpoint", ipc, "did not open within", timeout) |
||||
return proc |
||||
} |
||||
*/ |
Loading…
Reference in new issue