accountcmd_test.go 13 KB

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