ct_wallet.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. test.cmdtest_d.ct_wallet: Wallet conversion tests for the cmdtest.py test suite
  20. """
  21. import sys, os
  22. from mmgen.util import msg, capfirst, get_extension
  23. from mmgen.wallet import get_wallet_cls
  24. from ..include.common import cfg, joinpath, VirtBlockDevice
  25. from .common import ref_dir, ref_wallet_brainpass, ref_wallet_incog_offset, hincog_fn, hincog_bytes
  26. from .ct_base import CmdTestBase
  27. from .ct_shared import CmdTestShared
  28. class CmdTestWalletConv(CmdTestBase, CmdTestShared):
  29. 'wallet conversion to and from reference data'
  30. networks = ('btc',)
  31. tmpdir_nums = [11, 12, 13]
  32. sources = {
  33. '128': {
  34. 'ref_wallet': 'FE3C6545-D782B529[128,1].mmdat',
  35. 'ic_wallet': 'FE3C6545-E29303EA-5E229E30[128,1].mmincog',
  36. 'ic_wallet_hex': 'FE3C6545-BC4BE3F2-32586837[128,1].mmincox',
  37. 'hic_wallet': 'FE3C6545-161E495F-BEB7548E[128,1].incog-offset123',
  38. 'hic_wallet_old': 'FE3C6545-161E495F-9860A85B[128,1].incog-old.offset123',
  39. },
  40. '192': {
  41. 'ref_wallet': '1378FC64-6F0F9BB4[192,1].mmdat',
  42. 'ic_wallet': '1378FC64-2907DE97-F980D21F[192,1].mmincog',
  43. 'ic_wallet_hex': '1378FC64-4DCB5174-872806A7[192,1].mmincox',
  44. 'hic_wallet': '1378FC64-B55E9958-77256FC1[192,1].incog.offset123',
  45. 'hic_wallet_old': '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
  46. },
  47. '256': {
  48. 'ref_wallet': '98831F3A-27F2BF93[256,1].mmdat',
  49. 'ic_wallet': '98831F3A-5482381C-18460FB1[256,1].mmincog',
  50. 'ic_wallet_hex': '98831F3A-1630A9F2-870376A9[256,1].mmincox',
  51. 'hic_wallet': '98831F3A-F59B07A0-559CEF19[256,1].incog.offset123',
  52. 'hic_wallet_old': '98831F3A-F59B07A0-848535F3[256,1].incog-old.offset123',
  53. },
  54. }
  55. cmd_group = (
  56. # reading
  57. ('ref_wallet_conv', 'conversion of saved reference wallet'),
  58. ('ref_mn_conv', 'conversion of saved MMGen native mnemonic'),
  59. ('ref_bip39_conv', 'conversion of saved BIP39 mnemonic'),
  60. ('ref_seed_conv', 'conversion of saved seed file'),
  61. ('ref_hex_conv', 'conversion of saved MMGen hexadecimal seed file'),
  62. ('ref_plainhex_conv', 'conversion of saved plain hexadecimal seed file'),
  63. ('ref_dieroll_conv', 'conversion of saved dieroll (b6d) seed file'),
  64. ('ref_brain_conv', 'conversion of ref brainwallet'),
  65. ('ref_incog_conv', 'conversion of saved incog wallet'),
  66. ('ref_incox_conv', 'conversion of saved hex incog wallet'),
  67. ('ref_hincog_conv', 'conversion of saved hidden incog wallet'),
  68. ('ref_hincog_conv_old', 'conversion of saved hidden incog wallet (old format)'),
  69. # writing
  70. ('ref_wallet_conv_out', 'ref seed conversion to wallet'),
  71. ('ref_mn_conv_out', 'ref seed conversion to MMGen native mnemonic'),
  72. ('ref_bip39_conv_out', 'ref seed conversion to BIP39 mnemonic'),
  73. ('ref_hex_conv_out', 'ref seed conversion to MMGen hex seed'),
  74. ('ref_plainhex_conv_out', 'ref seed conversion to plain hex seed'),
  75. ('ref_dieroll_conv_out', 'ref seed conversion to dieroll (b6d) seed'),
  76. ('ref_seed_conv_out', 'ref seed conversion to seed'),
  77. ('ref_incog_conv_out', 'ref seed conversion to incog data'),
  78. ('ref_incox_conv_out', 'ref seed conversion to hex incog data'),
  79. ('ref_hincog_conv_out', 'ref seed conversion to hidden incog data'),
  80. ('ref_hincog_blkdev_conv_out', 'ref seed conversion to hidden incog data on block device')
  81. )
  82. def __init__(self, trunner, cfgs, spawn):
  83. for k, _ in self.cmd_group:
  84. for n in (1, 2, 3):
  85. setattr(self, f'{k}_{n}', getattr(self, k))
  86. CmdTestBase.__init__(self, trunner, cfgs, spawn)
  87. def ref_wallet_conv(self):
  88. wf = joinpath(ref_dir, self.sources[str(self.seed_len)]['ref_wallet'])
  89. return self.walletconv_in(wf)
  90. def ref_mn_conv(self, ext='mmwords'):
  91. wf = joinpath(ref_dir, self.seed_id+'.'+ext)
  92. return self.walletconv_in(wf)
  93. def ref_bip39_conv(self):
  94. return self.ref_mn_conv(ext='bip39')
  95. def ref_seed_conv(self):
  96. return self.ref_mn_conv(ext='mmseed')
  97. def ref_hex_conv(self):
  98. return self.ref_mn_conv(ext='mmhex')
  99. def ref_plainhex_conv(self):
  100. return self.ref_mn_conv(ext='hex')
  101. def ref_dieroll_conv(self):
  102. return self.ref_mn_conv(ext='b6d')
  103. def ref_brain_conv(self):
  104. uopts = ['-i', 'bw', '-p', '1', '-l', str(self.seed_len)]
  105. return self.walletconv_in(None, uopts, icls=get_wallet_cls('brain'))
  106. def ref_incog_conv(self, wfk='ic_wallet', in_fmt='i'):
  107. uopts = ['-i', in_fmt, '-p', '1', '-l', str(self.seed_len)]
  108. wf = joinpath(ref_dir, self.sources[str(self.seed_len)][wfk])
  109. return self.walletconv_in(wf, uopts)
  110. def ref_incox_conv(self):
  111. return self.ref_incog_conv(in_fmt='xi', wfk='ic_wallet_hex')
  112. def ref_hincog_conv(self, wfk='hic_wallet', add_uopts=[]):
  113. ic_f = joinpath(ref_dir, self.sources[str(self.seed_len)][wfk])
  114. uopts = ['-i', 'hi', '-p', '1', '-l', str(self.seed_len)] + add_uopts
  115. hi_opt = ['-H', f'{ic_f},{ref_wallet_incog_offset}']
  116. return self.walletconv_in(
  117. None,
  118. uopts + hi_opt,
  119. icls = get_wallet_cls('incog_hidden'))
  120. def ref_hincog_conv_old(self):
  121. return self.ref_hincog_conv(wfk='hic_wallet_old', add_uopts=['-O'])
  122. def ref_wallet_conv_out(self):
  123. return self.walletconv_out('w')
  124. def ref_mn_conv_out(self):
  125. return self.walletconv_out('mn')
  126. def ref_bip39_conv_out(self):
  127. return self.walletconv_out('bip39')
  128. def ref_seed_conv_out(self):
  129. return self.walletconv_out('seed')
  130. def ref_hex_conv_out(self):
  131. return self.walletconv_out('hexseed')
  132. def ref_plainhex_conv_out(self):
  133. return self.walletconv_out('hex')
  134. def ref_dieroll_conv_out(self):
  135. return self.walletconv_out('dieroll')
  136. def ref_incog_conv_out(self):
  137. return self.walletconv_out('i')
  138. def ref_incox_conv_out(self):
  139. return self.walletconv_out('xi')
  140. def ref_hincog_conv_out(self, ic_f=None):
  141. if not ic_f:
  142. ic_f = joinpath(self.tmpdir, hincog_fn)
  143. hi_parms = f'{ic_f},{ref_wallet_incog_offset}'
  144. sl_parm = '-l' + str(self.seed_len)
  145. return self.walletconv_out(
  146. 'hi',
  147. uopts = ['-J', hi_parms, sl_parm],
  148. uopts_chk = ['-H', hi_parms, sl_parm])
  149. def ref_hincog_blkdev_conv_out(self):
  150. if self.skip_for_win('no loop device'):
  151. return 'skip'
  152. b = VirtBlockDevice(os.path.join(self.tmpdir, 'hincog_blkdev_img'), '1K')
  153. b.create()
  154. b.attach(dev_mode='0666' if sys.platform == 'linux' else None)
  155. self.ref_hincog_conv_out(ic_f=b.dev)
  156. b.detach()
  157. return 'ok'
  158. # wallet conversion tests
  159. def walletconv_in(self, infile, uopts=[], icls=None):
  160. ocls = get_wallet_cls('words')
  161. opts = ['-d', self.tmpdir, '-o', ocls.fmt_codes[0], self.usr_rand_arg]
  162. if_arg = [infile] if infile else []
  163. d = '(convert)'
  164. t = self.spawn('mmgen-walletconv', opts+uopts+if_arg, extra_desc=d)
  165. t.license()
  166. icls = icls or get_wallet_cls(ext=get_extension(infile))
  167. if icls.type == 'brain':
  168. t.expect('Enter brainwallet: ', ref_wallet_brainpass+'\n')
  169. if icls.enc and icls.type != 'brain':
  170. t.passphrase(icls.desc, self.wpasswd)
  171. if self.test_name[:19] == 'ref_hincog_conv_old':
  172. t.expect('Is the Seed ID correct? (Y/n): ', '\n')
  173. else:
  174. t.expect(['Passphrase is OK', ' are correct'])
  175. wf = t.written_to_file(capfirst(ocls.desc))
  176. t.p.wait()
  177. # back check of result
  178. msg('' if cfg.profile else ' OK')
  179. return self.walletchk(
  180. wf,
  181. extra_desc = '(check)',
  182. sid = self.seed_id)
  183. def walletconv_out(self, out_fmt='w', uopts=[], uopts_chk=[]):
  184. wcls = get_wallet_cls(fmt_code=out_fmt)
  185. opts = ['-d', self.tmpdir, '-p1', '-o', out_fmt] + uopts
  186. infile = joinpath(ref_dir, self.seed_id+'.mmwords')
  187. t = self.spawn('mmgen-walletconv', [self.usr_rand_arg]+opts+[infile], extra_desc='(convert)')
  188. add_args = [f'-l{self.seed_len}']
  189. t.license()
  190. if wcls.enc and wcls.type != 'brain':
  191. t.passphrase_new('new '+wcls.desc, self.wpasswd)
  192. t.usr_rand(self.usr_rand_chars)
  193. if wcls.type.startswith('incog'):
  194. for _ in range(3):
  195. t.expect('Encrypting random data from your operating system with ephemeral key')
  196. if wcls.type == 'incog_hidden':
  197. t.hincog_create(hincog_bytes)
  198. if out_fmt == 'w':
  199. t.label()
  200. wf = t.written_to_file(capfirst(wcls.desc))
  201. if wcls.type == 'incog_hidden':
  202. add_args += uopts_chk
  203. wf = None
  204. msg('' if cfg.profile else ' OK')
  205. return self.walletchk(
  206. wf,
  207. wcls = wcls,
  208. extra_desc = '(check)',
  209. sid = self.seed_id,
  210. add_args = add_args)