accountcmd_test.go 12 KB

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