github.com/core-coin/go-core/v2@v2.1.9/cmd/gocore/accountcmd_test.go (about)

     1  // Copyright 2023 by the Authors
     2  // This file is part of go-core.
     3  //
     4  // go-core is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-core is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-core. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"path/filepath"
    23  	"runtime"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/cespare/cp"
    28  )
    29  
    30  // These tests are 'smoke tests' for the account related
    31  // subcommands and flags.
    32  //
    33  // For most tests, the test files from package accounts
    34  // are copied into a temporary keystore directory.
    35  
    36  func tmpDatadirWithKeystore(t *testing.T) string {
    37  	datadir := tmpdir(t)
    38  	keystore := filepath.Join(datadir, "keystore")
    39  	source := filepath.Join("..", "..", "accounts", "keystore", "testdata", "keystore")
    40  	if err := cp.CopyAll(keystore, source); err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	fmt.Println(keystore)
    44  	return datadir
    45  }
    46  
    47  func TestAccountListEmpty(t *testing.T) {
    48  	gocore := runGocore(t, "account", "list")
    49  	gocore.ExpectExit()
    50  }
    51  
    52  func TestAccountList(t *testing.T) {
    53  	datadir := tmpDatadirWithKeystore(t)
    54  	gocore := runGocore(t, "account", "list", "--datadir", datadir)
    55  	defer gocore.ExpectExit()
    56  	if runtime.GOOS == "windows" {
    57  		gocore.Expect(`
    58  Account #0: {cb27de521e43741cf785cbad450d5649187b9612018f} keystore://{{.Datadir}}\keystore\UTC--2020-07-20T17-37-08.515483762Z--cb27de521e43741cf785cbad450d5649187b9612018f
    59  Account #1: {cb74db416ff2f9c53dabaf34f81142db30350ea7b144} keystore://{{.Datadir}}\keystore\aaa
    60  Account #2: {cb65e49851f010cd7d81b5b4969f3b0e8325c415359d} keystore://{{.Datadir}}\keystore\zzz
    61  `)
    62  	} else {
    63  		gocore.Expect(`
    64  Account #0: {cb27de521e43741cf785cbad450d5649187b9612018f} keystore://{{.Datadir}}/keystore/UTC--2020-07-20T17-37-08.515483762Z--cb27de521e43741cf785cbad450d5649187b9612018f
    65  Account #1: {cb74db416ff2f9c53dabaf34f81142db30350ea7b144} keystore://{{.Datadir}}/keystore/aaa
    66  Account #2: {cb65e49851f010cd7d81b5b4969f3b0e8325c415359d} keystore://{{.Datadir}}/keystore/zzz
    67  `)
    68  	}
    69  }
    70  
    71  func TestAccountNew(t *testing.T) {
    72  	gocore := runGocore(t, "account", "new", "--lightkdf")
    73  	defer gocore.ExpectExit()
    74  	gocore.Expect(`
    75  Your new account is locked with a password. Please give a password. Do not forget this password.
    76  !! Unsupported terminal, password will be echoed.
    77  Password: {{.InputLine "foobar"}}
    78  Repeat password: {{.InputLine "foobar"}}
    79  
    80  Your new key was generated
    81  `)
    82  	gocore.ExpectRegexp(`
    83  Public address of the key:   [0-9a-fA-F]{44}
    84  Path of the secret key file: .*UTC--.+--[0-9a-f]{44}
    85  
    86  - You can share your public address with anyone. Others need it to interact with you.
    87  - You must NEVER share the secret key with anyone! The key controls access to your funds!
    88  - You must BACKUP your key file! Without the key, it's impossible to access account funds!
    89  - You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
    90  `)
    91  }
    92  
    93  func TestAccountImport(t *testing.T) {
    94  	tests := []struct{ name, key, output string }{
    95  		{
    96  			name:   "correct account",
    97  			key:    "69bb68c3a00a0cd9cbf2cab316476228c758329bbfe0b1759e8634694a9497afea05bcbf24e2aa0627eac4240484bb71de646a9296872a3c0e",
    98  			output: "Address: {fcad0b19bb29d4674531d6f115237e16afce377c}\n",
    99  		},
   100  		{
   101  			name:   "invalid character",
   102  			key:    "69bb68c3a00a0cd9cbf2cab316476228c758329bbfe0b1759e8634694a9497afea05bcbf24e2aa0627eac4240484bb71de646a9296872a3c0e1",
   103  			output: "Fatal: Failed to load the private key: invalid character '1' at end of key file\n",
   104  		},
   105  	}
   106  	for _, test := range tests {
   107  		t.Run(test.name, func(t *testing.T) {
   108  			t.Parallel()
   109  			importAccountWithExpect(t, test.key, test.output)
   110  		})
   111  	}
   112  }
   113  
   114  func importAccountWithExpect(t *testing.T, key string, expected string) {
   115  	dir := tmpdir(t)
   116  	keyfile := filepath.Join(dir, "key.prv")
   117  	if err := ioutil.WriteFile(keyfile, []byte(key), 0600); err != nil {
   118  		t.Error(err)
   119  	}
   120  	passwordFile := filepath.Join(dir, "password.txt")
   121  	if err := ioutil.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil {
   122  		t.Error(err)
   123  	}
   124  	gocore := runGocore(t, "account", "import", keyfile, "-password", passwordFile)
   125  	defer gocore.ExpectExit()
   126  	gocore.Expect(expected)
   127  }
   128  
   129  func TestAccountNewBadRepeat(t *testing.T) {
   130  	gocore := runGocore(t, "account", "new", "--lightkdf")
   131  	defer gocore.ExpectExit()
   132  	gocore.Expect(`
   133  Your new account is locked with a password. Please give a password. Do not forget this password.
   134  !! Unsupported terminal, password will be echoed.
   135  Password: {{.InputLine "something"}}
   136  Repeat password: {{.InputLine "something else"}}
   137  Fatal: Passwords do not match
   138  `)
   139  }
   140  
   141  func TestAccountUpdate(t *testing.T) {
   142  	datadir := tmpDatadirWithKeystore(t)
   143  	gocore := runGocore(t, "account", "update",
   144  		"--datadir", datadir, "--lightkdf",
   145  		"cb74db416ff2f9c53dabaf34f81142db30350ea7b144")
   146  	defer gocore.ExpectExit()
   147  	gocore.Expect(`
   148  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 1/3
   149  !! Unsupported terminal, password will be echoed.
   150  Password: {{.InputLine "foobar"}}
   151  Please give a new password. Do not forget this password.
   152  Password: {{.InputLine "foobar"}}
   153  Repeat password: {{.InputLine "foobar"}}
   154  `)
   155  }
   156  
   157  func TestUnlockFlag(t *testing.T) {
   158  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   159  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "js", "testdata/empty.js")
   160  	gocore.Expect(`
   161  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 1/3
   162  !! Unsupported terminal, password will be echoed.
   163  Password: {{.InputLine "foobar"}}
   164  `)
   165  	gocore.ExpectExit()
   166  
   167  	wantMessages := []string{
   168  		"Unlocked account",
   169  		"=cb74db416ff2f9c53dabaf34f81142db30350ea7b144",
   170  	}
   171  	for _, m := range wantMessages {
   172  		if !strings.Contains(gocore.StderrText(), m) {
   173  			t.Errorf("stderr text does not contain %q", m)
   174  		}
   175  	}
   176  }
   177  
   178  func TestUnlockFlagWrongPassword(t *testing.T) {
   179  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   180  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "js", "testdata/empty.js")
   181  
   182  	defer gocore.ExpectExit()
   183  	gocore.Expect(`
   184  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 1/3
   185  !! Unsupported terminal, password will be echoed.
   186  Password: {{.InputLine "wrong1"}}
   187  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 2/3
   188  Password: {{.InputLine "wrong2"}}
   189  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 3/3
   190  Password: {{.InputLine "wrong3"}}
   191  Fatal: Failed to unlock account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 (could not decrypt key with given password)
   192  `)
   193  }
   194  
   195  // https://github.com/core-coin/go-core/v2/issues/1785
   196  func TestUnlockFlagMultiIndex(t *testing.T) {
   197  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   198  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "--unlock", "0,2", "js", "testdata/empty.js")
   199  
   200  	gocore.Expect(`
   201  Unlocking account 0 | Attempt 1/3
   202  !! Unsupported terminal, password will be echoed.
   203  Password: {{.InputLine "foobar"}}
   204  Unlocking account 2 | Attempt 1/3
   205  Password: {{.InputLine "foobar"}}
   206  `)
   207  	gocore.ExpectExit()
   208  
   209  	wantMessages := []string{
   210  		"Unlocked account",
   211  		"=cb27de521e43741cf785cbad450d5649187b9612018f",
   212  		"=cb65e49851f010cd7d81b5b4969f3b0e8325c415359d",
   213  	}
   214  	for _, m := range wantMessages {
   215  		if !strings.Contains(gocore.StderrText(), m) {
   216  			t.Errorf("stderr text does not contain %q", m)
   217  		}
   218  	}
   219  }
   220  
   221  func TestUnlockFlagPasswordFile(t *testing.T) {
   222  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   223  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "--password", "testdata/passwords.txt", "--unlock", "0,2", "js", "testdata/empty.js")
   224  
   225  	gocore.ExpectExit()
   226  
   227  	wantMessages := []string{
   228  		"Unlocked account",
   229  		"=cb27de521e43741cf785cbad450d5649187b9612018f",
   230  		"=cb65e49851f010cd7d81b5b4969f3b0e8325c415359d",
   231  	}
   232  	for _, m := range wantMessages {
   233  		if !strings.Contains(gocore.StderrText(), m) {
   234  			t.Errorf("stderr text does not contain %q", m)
   235  		}
   236  	}
   237  }
   238  
   239  func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
   240  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   241  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "--password",
   242  		"testdata/wrong-passwords.txt", "--unlock", "0,2")
   243  	defer gocore.ExpectExit()
   244  	gocore.Expect(`
   245  Fatal: Failed to unlock account 0 (could not decrypt key with given password)
   246  `)
   247  }
   248  
   249  func TestUnlockFlagAmbiguous(t *testing.T) {
   250  	store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
   251  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   252  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "--keystore",
   253  		store, "--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144",
   254  		"js", "testdata/empty.js")
   255  	defer gocore.ExpectExit()
   256  
   257  	// Helper for the expect template, returns absolute keystore path.
   258  	gocore.SetTemplateFunc("keypath", func(file string) string {
   259  		abs, _ := filepath.Abs(filepath.Join(store, file))
   260  		return abs
   261  	})
   262  	gocore.Expect(`
   263  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 1/3
   264  !! Unsupported terminal, password will be echoed.
   265  Password: {{.InputLine "foobar"}}
   266  Multiple key files exist for address cb74db416ff2f9c53dabaf34f81142db30350ea7b144:
   267     keystore://{{keypath "1"}}
   268     keystore://{{keypath "2"}}
   269  Testing your password against all of them...
   270  Your password unlocked keystore://{{keypath "1"}}
   271  In order to avoid this warning, you need to remove the following duplicate key files:
   272     keystore://{{keypath "2"}}
   273  `)
   274  	gocore.ExpectExit()
   275  
   276  	wantMessages := []string{
   277  		"Unlocked account",
   278  		"=cb74db416ff2f9c53dabaf34f81142db30350ea7b144",
   279  	}
   280  	for _, m := range wantMessages {
   281  		if !strings.Contains(gocore.StderrText(), m) {
   282  			t.Errorf("stderr text does not contain %q", m)
   283  		}
   284  	}
   285  }
   286  
   287  func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
   288  	store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
   289  	gocore := runMinimalGocore(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
   290  		"--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144", "--keystore",
   291  		store, "--unlock", "cb74db416ff2f9c53dabaf34f81142db30350ea7b144")
   292  
   293  	defer gocore.ExpectExit()
   294  
   295  	// Helper for the expect template, returns absolute keystore path.
   296  	gocore.SetTemplateFunc("keypath", func(file string) string {
   297  		abs, _ := filepath.Abs(filepath.Join(store, file))
   298  		return abs
   299  	})
   300  	gocore.Expect(`
   301  Unlocking account cb74db416ff2f9c53dabaf34f81142db30350ea7b144 | Attempt 1/3
   302  !! Unsupported terminal, password will be echoed.
   303  Password: {{.InputLine "wrong"}}
   304  Multiple key files exist for address cb74db416ff2f9c53dabaf34f81142db30350ea7b144:
   305     keystore://{{keypath "1"}}
   306     keystore://{{keypath "2"}}
   307  Testing your password against all of them...
   308  Fatal: None of the listed files could be unlocked.
   309  `)
   310  	gocore.ExpectExit()
   311  }