github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/cmd/geth/accountcmd_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum 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-ethereum 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-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "os" 21 "path/filepath" 22 "runtime" 23 "strings" 24 "testing" 25 26 "github.com/cespare/cp" 27 ) 28 29 // These tests are 'smoke tests' for the account related 30 // subcommands and flags. 31 // 32 // For most tests, the test files from package accounts 33 // are copied into a temporary keystore directory. 34 35 func tmpDatadirWithKeystore(t *testing.T) string { 36 datadir := t.TempDir() 37 keystore := filepath.Join(datadir, "keystore") 38 source := filepath.Join("..", "..", "accounts", "keystore", "testdata", "keystore") 39 if err := cp.CopyAll(keystore, source); err != nil { 40 t.Fatal(err) 41 } 42 return datadir 43 } 44 45 func TestAccountListEmpty(t *testing.T) { 46 t.Parallel() 47 geth := runGeth(t, "account", "list") 48 geth.ExpectExit() 49 } 50 51 func TestAccountList(t *testing.T) { 52 t.Parallel() 53 datadir := tmpDatadirWithKeystore(t) 54 var want = ` 55 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 56 Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa 57 Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz 58 ` 59 if runtime.GOOS == "windows" { 60 want = ` 61 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 62 Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa 63 Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz 64 ` 65 } 66 { 67 geth := runGeth(t, "account", "list", "--datadir", datadir) 68 geth.Expect(want) 69 geth.ExpectExit() 70 } 71 { 72 geth := runGeth(t, "--datadir", datadir, "account", "list") 73 geth.Expect(want) 74 geth.ExpectExit() 75 } 76 } 77 78 func TestAccountNew(t *testing.T) { 79 t.Parallel() 80 geth := runGeth(t, "account", "new", "--lightkdf") 81 defer geth.ExpectExit() 82 geth.Expect(` 83 Your new account is locked with a password. Please give a password. Do not forget this password. 84 !! Unsupported terminal, password will be echoed. 85 Password: {{.InputLine "foobar"}} 86 Repeat password: {{.InputLine "foobar"}} 87 88 Your new key was generated 89 `) 90 geth.ExpectRegexp(` 91 Public address of the key: 0x[0-9a-fA-F]{40} 92 Path of the secret key file: .*UTC--.+--[0-9a-f]{40} 93 94 - You can share your public address with anyone. Others need it to interact with you. 95 - You must NEVER share the secret key with anyone! The key controls access to your funds! 96 - You must BACKUP your key file! Without the key, it's impossible to access account funds! 97 - You must REMEMBER your password! Without the password, it's impossible to decrypt the key! 98 `) 99 } 100 101 func TestAccountImport(t *testing.T) { 102 t.Parallel() 103 tests := []struct{ name, key, output string }{ 104 { 105 name: "correct account", 106 key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", 107 output: "Address: {fcad0b19bb29d4674531d6f115237e16afce377c}\n", 108 }, 109 { 110 name: "invalid character", 111 key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef1", 112 output: "Fatal: Failed to load the private key: invalid character '1' at end of key file\n", 113 }, 114 } 115 for _, test := range tests { 116 test := test 117 t.Run(test.name, func(t *testing.T) { 118 t.Parallel() 119 importAccountWithExpect(t, test.key, test.output) 120 }) 121 } 122 } 123 124 func TestAccountHelp(t *testing.T) { 125 t.Parallel() 126 geth := runGeth(t, "account", "-h") 127 geth.WaitExit() 128 if have, want := geth.ExitStatus(), 0; have != want { 129 t.Errorf("exit error, have %d want %d", have, want) 130 } 131 132 geth = runGeth(t, "account", "import", "-h") 133 geth.WaitExit() 134 if have, want := geth.ExitStatus(), 0; have != want { 135 t.Errorf("exit error, have %d want %d", have, want) 136 } 137 } 138 139 func importAccountWithExpect(t *testing.T, key string, expected string) { 140 dir := t.TempDir() 141 keyfile := filepath.Join(dir, "key.prv") 142 if err := os.WriteFile(keyfile, []byte(key), 0600); err != nil { 143 t.Error(err) 144 } 145 passwordFile := filepath.Join(dir, "password.txt") 146 if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil { 147 t.Error(err) 148 } 149 geth := runGeth(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile) 150 defer geth.ExpectExit() 151 geth.Expect(expected) 152 } 153 154 func TestAccountNewBadRepeat(t *testing.T) { 155 t.Parallel() 156 geth := runGeth(t, "account", "new", "--lightkdf") 157 defer geth.ExpectExit() 158 geth.Expect(` 159 Your new account is locked with a password. Please give a password. Do not forget this password. 160 !! Unsupported terminal, password will be echoed. 161 Password: {{.InputLine "something"}} 162 Repeat password: {{.InputLine "something else"}} 163 Fatal: Passwords do not match 164 `) 165 } 166 167 func TestAccountUpdate(t *testing.T) { 168 t.Parallel() 169 datadir := tmpDatadirWithKeystore(t) 170 geth := runGeth(t, "account", "update", 171 "--datadir", datadir, "--lightkdf", 172 "f466859ead1932d743d622cb74fc058882e8648a") 173 defer geth.ExpectExit() 174 geth.Expect(` 175 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 176 !! Unsupported terminal, password will be echoed. 177 Password: {{.InputLine "foobar"}} 178 Please give a new password. Do not forget this password. 179 Password: {{.InputLine "foobar2"}} 180 Repeat password: {{.InputLine "foobar2"}} 181 `) 182 } 183 184 func TestWalletImport(t *testing.T) { 185 t.Parallel() 186 geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") 187 defer geth.ExpectExit() 188 geth.Expect(` 189 !! Unsupported terminal, password will be echoed. 190 Password: {{.InputLine "foo"}} 191 Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f} 192 `) 193 194 files, err := os.ReadDir(filepath.Join(geth.Datadir, "keystore")) 195 if len(files) != 1 { 196 t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err) 197 } 198 } 199 200 func TestWalletImportBadPassword(t *testing.T) { 201 t.Parallel() 202 geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") 203 defer geth.ExpectExit() 204 geth.Expect(` 205 !! Unsupported terminal, password will be echoed. 206 Password: {{.InputLine "wrong"}} 207 Fatal: could not decrypt key with given password 208 `) 209 } 210 211 func TestUnlockFlag(t *testing.T) { 212 t.Parallel() 213 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 214 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')") 215 geth.Expect(` 216 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 217 !! Unsupported terminal, password will be echoed. 218 Password: {{.InputLine "foobar"}} 219 undefined 220 `) 221 geth.ExpectExit() 222 223 wantMessages := []string{ 224 "Unlocked account", 225 "=0xf466859eAD1932D743d622CB74FC058882E8648A", 226 } 227 for _, m := range wantMessages { 228 if !strings.Contains(geth.StderrText(), m) { 229 t.Errorf("stderr text does not contain %q", m) 230 } 231 } 232 } 233 234 func TestUnlockFlagWrongPassword(t *testing.T) { 235 t.Parallel() 236 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 237 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')") 238 239 defer geth.ExpectExit() 240 geth.Expect(` 241 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 242 !! Unsupported terminal, password will be echoed. 243 Password: {{.InputLine "wrong1"}} 244 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 2/3 245 Password: {{.InputLine "wrong2"}} 246 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 3/3 247 Password: {{.InputLine "wrong3"}} 248 Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given password) 249 `) 250 } 251 252 // https://github.com/ethereum/go-ethereum/issues/1785 253 func TestUnlockFlagMultiIndex(t *testing.T) { 254 t.Parallel() 255 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 256 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')") 257 258 geth.Expect(` 259 Unlocking account 0 | Attempt 1/3 260 !! Unsupported terminal, password will be echoed. 261 Password: {{.InputLine "foobar"}} 262 Unlocking account 2 | Attempt 1/3 263 Password: {{.InputLine "foobar"}} 264 undefined 265 `) 266 geth.ExpectExit() 267 268 wantMessages := []string{ 269 "Unlocked account", 270 "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", 271 "=0x289d485D9771714CCe91D3393D764E1311907ACc", 272 } 273 for _, m := range wantMessages { 274 if !strings.Contains(geth.StderrText(), m) { 275 t.Errorf("stderr text does not contain %q", m) 276 } 277 } 278 } 279 280 func TestUnlockFlagPasswordFile(t *testing.T) { 281 t.Parallel() 282 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 283 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password", "testdata/passwords.txt", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')") 284 285 geth.Expect(` 286 undefined 287 `) 288 geth.ExpectExit() 289 290 wantMessages := []string{ 291 "Unlocked account", 292 "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", 293 "=0x289d485D9771714CCe91D3393D764E1311907ACc", 294 } 295 for _, m := range wantMessages { 296 if !strings.Contains(geth.StderrText(), m) { 297 t.Errorf("stderr text does not contain %q", m) 298 } 299 } 300 } 301 302 func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) { 303 t.Parallel() 304 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 305 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password", 306 "testdata/wrong-passwords.txt", "--unlock", "0,2") 307 defer geth.ExpectExit() 308 geth.Expect(` 309 Fatal: Failed to unlock account 0 (could not decrypt key with given password) 310 `) 311 } 312 313 func TestUnlockFlagAmbiguous(t *testing.T) { 314 t.Parallel() 315 store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") 316 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 317 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--keystore", 318 store, "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", 319 "console", "--exec", "loadScript('testdata/empty.js')") 320 defer geth.ExpectExit() 321 322 // Helper for the expect template, returns absolute keystore path. 323 geth.SetTemplateFunc("keypath", func(file string) string { 324 abs, _ := filepath.Abs(filepath.Join(store, file)) 325 return abs 326 }) 327 geth.Expect(` 328 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 329 !! Unsupported terminal, password will be echoed. 330 Password: {{.InputLine "foobar"}} 331 Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: 332 keystore://{{keypath "1"}} 333 keystore://{{keypath "2"}} 334 Testing your password against all of them... 335 Your password unlocked keystore://{{keypath "1"}} 336 In order to avoid this warning, you need to remove the following duplicate key files: 337 keystore://{{keypath "2"}} 338 undefined 339 `) 340 geth.ExpectExit() 341 342 wantMessages := []string{ 343 "Unlocked account", 344 "=0xf466859eAD1932D743d622CB74FC058882E8648A", 345 } 346 for _, m := range wantMessages { 347 if !strings.Contains(geth.StderrText(), m) { 348 t.Errorf("stderr text does not contain %q", m) 349 } 350 } 351 } 352 353 func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) { 354 t.Parallel() 355 store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") 356 geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), 357 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--keystore", 358 store, "--unlock", "f466859ead1932d743d622cb74fc058882e8648a") 359 360 defer geth.ExpectExit() 361 362 // Helper for the expect template, returns absolute keystore path. 363 geth.SetTemplateFunc("keypath", func(file string) string { 364 abs, _ := filepath.Abs(filepath.Join(store, file)) 365 return abs 366 }) 367 geth.Expect(` 368 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 369 !! Unsupported terminal, password will be echoed. 370 Password: {{.InputLine "wrong"}} 371 Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: 372 keystore://{{keypath "1"}} 373 keystore://{{keypath "2"}} 374 Testing your password against all of them... 375 Fatal: None of the listed files could be unlocked. 376 `) 377 geth.ExpectExit() 378 }