test.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. #!/usr/bin/python
  2. # Chdir to repo root.
  3. # Since script is not in repo root, fix sys.path so that modules are
  4. # imported from repo, not system.
  5. import sys,os
  6. pn = os.path.dirname(sys.argv[0])
  7. os.chdir(os.path.join(pn,os.pardir))
  8. sys.path.__setitem__(0,os.path.abspath(os.curdir))
  9. import mmgen.config as g
  10. import mmgen.opt as opt
  11. from mmgen.util import msgrepr,msgrepr_exit,Msg
  12. from mmgen.test import *
  13. hincog_fn = "rand_data"
  14. non_mmgen_fn = "btckey"
  15. cfgs = {
  16. '6': {
  17. 'name': "reference wallet check",
  18. 'bw_passwd': "abc",
  19. 'bw_hashparams': "256,1",
  20. 'key_id': "98831F3A",
  21. 'addrfile_chk': "6FEF 6FB9 7B13 5D91 854A 0BD3",
  22. 'keyaddrfile_chk': "9F2D D781 1812 8BAD C396 9DEB",
  23. 'wpasswd': "reference password",
  24. 'tmpdir': "test/tmp6",
  25. 'kapasswd': "",
  26. 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses
  27. 'dep_generators': {
  28. 'mmdat': "refwalletgen",
  29. 'addrs': "refaddrgen",
  30. 'akeys.mmenc': "refkeyaddrgen"
  31. },
  32. },
  33. '1': {
  34. 'tmpdir': "test/tmp1",
  35. 'wpasswd': "Dorian",
  36. 'kapasswd': "Grok the blockchain",
  37. 'addr_idx_list': "12,99,5-10,5,12", # 8 addresses
  38. 'dep_generators': {
  39. 'mmdat': "walletgen",
  40. 'addrs': "addrgen",
  41. 'raw': "txcreate",
  42. 'sig': "txsign",
  43. 'mmwords': "export_mnemonic",
  44. 'mmseed': "export_seed",
  45. 'mmincog': "export_incog",
  46. 'mmincox': "export_incog_hex",
  47. hincog_fn: "export_incog_hidden",
  48. 'akeys.mmenc': "keyaddrgen"
  49. },
  50. },
  51. '2': {
  52. 'tmpdir': "test/tmp2",
  53. 'wpasswd': "Hodling away",
  54. 'addr_idx_list': "37,45,3-6,22-23", # 8 addresses
  55. 'seed_len': 128,
  56. 'dep_generators': {
  57. 'mmdat': "walletgen2",
  58. 'addrs': "addrgen2",
  59. 'raw': "txcreate2",
  60. 'sig': "txsign2",
  61. 'mmwords': "export_mnemonic2",
  62. },
  63. },
  64. '3': {
  65. 'tmpdir': "test/tmp3",
  66. 'wpasswd': "Major miner",
  67. 'addr_idx_list': "73,54,1022-1023,2-5", # 8 addresses
  68. 'dep_generators': {
  69. 'mmdat': "walletgen3",
  70. 'addrs': "addrgen3",
  71. 'raw': "txcreate3",
  72. 'sig': "txsign3"
  73. },
  74. },
  75. '4': {
  76. 'tmpdir': "test/tmp4",
  77. 'wpasswd': "Hashrate rising",
  78. 'addr_idx_list': "63,1004,542-544,7-9", # 8 addresses
  79. 'seed_len': 192,
  80. 'dep_generators': {
  81. 'mmdat': "walletgen4",
  82. 'mmbrain': "walletgen4",
  83. 'addrs': "addrgen4",
  84. 'raw': "txcreate4",
  85. 'sig': "txsign4",
  86. },
  87. 'bw_filename': "brainwallet.mmbrain",
  88. 'bw_params': "192,1",
  89. },
  90. '5': {
  91. 'tmpdir': "test/tmp5",
  92. 'wpasswd': "My changed password",
  93. 'dep_generators': {
  94. 'mmdat': "passchg",
  95. },
  96. },
  97. '9': {
  98. 'tmpdir': "test/tmp9",
  99. 'tool_enc_passwd': "Scrypt it, don't hash it!",
  100. 'tool_enc_reftext':
  101. "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n",
  102. 'tool_enc_infn': "tool_encrypt.in",
  103. 'tool_enc_ref_infn': "tool_encrypt_ref.in",
  104. 'dep_generators': {
  105. 'tool_encrypt.in': "tool_encrypt",
  106. 'tool_encrypt.in.mmenc': "tool_encrypt",
  107. 'tool_encrypt_ref.in': "tool_encrypt_ref",
  108. 'tool_encrypt_ref.in.mmenc': "tool_encrypt_ref",
  109. },
  110. },
  111. }
  112. from collections import OrderedDict
  113. cmd_data = OrderedDict([
  114. # test description depends
  115. ['refwalletgen', (6,'reference wallet seed ID', [[[],6]])],
  116. ['refaddrgen', (6,'reference wallet address checksum', [[["mmdat"],6]])],
  117. ['refkeyaddrgen', (6,'reference wallet key-address checksum', [[["mmdat"],6]])],
  118. ['walletgen', (1,'wallet generation', [[[],1]])],
  119. ['walletchk', (1,'wallet check', [[["mmdat"],1]])],
  120. ['passchg', (5,'password, label and hash preset change',[[["mmdat"],1]])],
  121. ['walletchk_newpass',(5,'wallet check with new pw, label and hash preset',[[["mmdat"],5]])],
  122. ['addrgen', (1,'address generation', [[["mmdat"],1]])],
  123. ['addrimport', (1,'address import', [[["addrs"],1]])],
  124. ['txcreate', (1,'transaction creation', [[["addrs"],1]])],
  125. ['txsign', (1,'transaction signing', [[["mmdat","raw"],1]])],
  126. ['txsend', (1,'transaction sending', [[["sig"],1]])],
  127. ['export_seed', (1,'seed export to mmseed format', [[["mmdat"],1]])],
  128. ['export_mnemonic', (1,'seed export to mmwords format', [[["mmdat"],1]])],
  129. ['export_incog', (1,'seed export to mmincog format', [[["mmdat"],1]])],
  130. ['export_incog_hex',(1,'seed export to mmincog hex format', [[["mmdat"],1]])],
  131. ['export_incog_hidden',(1,'seed export to hidden mmincog format', [[["mmdat"],1]])],
  132. ['addrgen_seed', (1,'address generation from mmseed file', [[["mmseed","addrs"],1]])],
  133. ['addrgen_mnemonic',(1,'address generation from mmwords file',[[["mmwords","addrs"],1]])],
  134. ['addrgen_incog', (1,'address generation from mmincog file',[[["mmincog","addrs"],1]])],
  135. ['addrgen_incog_hex',(1,'address generation from mmincog hex file',[[["mmincox","addrs"],1]])],
  136. ['addrgen_incog_hidden',(1,'address generation from hidden mmincog file', [[[hincog_fn,"addrs"],1]])],
  137. ['keyaddrgen', (1,'key-address file generation', [[["mmdat"],1]])],
  138. ['txsign_keyaddr',(1,'transaction signing with key-address file', [[["akeys.mmenc","raw"],1]])],
  139. ['walletgen2',(2,'wallet generation (2)', [])],
  140. # ['walletgen2',(2,'wallet generation (2), 128-bit seed (WIP)', [])],
  141. ['addrgen2', (2,'address generation (2)', [[["mmdat"],2]])],
  142. ['txcreate2', (2,'transaction creation (2)', [[["addrs"],2]])],
  143. ['txsign2', (2,'transaction signing, two transactions',[[["mmdat","raw"],1],[["mmdat","raw"],2]])],
  144. ['export_mnemonic2', (2,'seed export to mmwords format (2)',[[["mmdat"],2]])],
  145. # ['export_mnemonic2', (2,'seed export to mmwords format (2), 128-bit seed (WIP)',[[["mmdat"],2]])],
  146. ['walletgen3',(3,'wallet generation (3)', [])],
  147. ['addrgen3', (3,'address generation (3)', [[["mmdat"],3]])],
  148. ['txcreate3', (3,'tx creation with inputs and outputs from two wallets', [[["addrs"],1],[["addrs"],3]])],
  149. ['txsign3', (3,'tx signing with inputs and outputs from two wallets',[[["mmdat"],1],[["mmdat","raw"],3]])],
  150. ['walletgen4',(4,'wallet generation (4) (brainwallet)', [])],
  151. # ['walletgen4',(4,'wallet generation (4) (brainwallet, 192-bit seed (WIP))', [])],
  152. ['addrgen4', (4,'address generation (4)', [[["mmdat"],4]])],
  153. ['txcreate4', (4,'tx creation with inputs and outputs from four seed sources, plus non-MMGen inputs and outputs', [[["addrs"],1],[["addrs"],2],[["addrs"],3],[["addrs"],4]])],
  154. ['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet and brainwallet, plus non-MMGen inputs and outputs', [[["mmincog"],1],[["mmwords"],2],[["mmdat"],3],[["mmbrain","raw"],4]])],
  155. ['tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [])],
  156. ['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)",
  157. [[[cfgs['9']['tool_enc_infn'],
  158. cfgs['9']['tool_enc_infn']+".mmenc"],9]])],
  159. ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])],
  160. ['tool_decrypt_ref', (9,"'mmgen-tool decrypt' (reference text)",
  161. [[[cfgs['9']['tool_enc_ref_infn'],
  162. cfgs['9']['tool_enc_ref_infn']+".mmenc"],9]])],
  163. ])
  164. utils = {
  165. 'check_deps': 'check dependencies for specified command',
  166. 'clean': 'clean specified tmp dir(s) 1,2,3,4,5 or 6 (no arg = all dirs)',
  167. }
  168. addrs_per_wallet = 8
  169. # total of two outputs must be < 10 BTC
  170. for k in cfgs.keys():
  171. cfgs[k]['amts'] = [0,0]
  172. for idx,mod in (0,6),(1,4):
  173. cfgs[k]['amts'][idx] = "%s.%s" % ((getrandnum(2) % mod), str(getrandnum(4))[:5])
  174. meta_cmds = OrderedDict([
  175. ['ref', (6,("refwalletgen","refaddrgen","refkeyaddrgen"))],
  176. ['gen', (1,("walletgen","walletchk","addrgen"))],
  177. ['pass', (5,("passchg","walletchk_newpass"))],
  178. ['tx', (1,("txcreate","txsign","txsend"))],
  179. ['export', (1,[k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1])],
  180. ['gen_sp', (1,[k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1])],
  181. ['online', (1,("keyaddrgen","txsign_keyaddr"))],
  182. ['2', (2,[k for k in cmd_data if cmd_data[k][0] == 2])],
  183. ['3', (3,[k for k in cmd_data if cmd_data[k][0] == 3])],
  184. ['4', (4,[k for k in cmd_data if cmd_data[k][0] == 4])],
  185. ['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref"))],
  186. ])
  187. opts_data = {
  188. 'desc': "Test suite for the MMGen suite",
  189. 'usage':"[options] [command or metacommand]",
  190. 'options': """
  191. -h, --help Print this help message
  192. -b, --buf-keypress Use buffered keypresses as with real human input
  193. -d, --debug Produce debugging output
  194. -D, --direct-exec Bypass pexpect and execute a command directly (for debugging only)
  195. -e, --exact-output Show the exact output of the MMGen script(s) being run
  196. -l, --list-cmds List and describe the tests and commands in the test suite
  197. -p, --pause Pause between tests, resuming on keypress
  198. -q, --quiet Produce minimal output. Suppress dependency info
  199. -s, --system Test scripts and modules installed on system rather than those in the repo root
  200. -v, --verbose Produce more verbose output
  201. """,
  202. 'notes': """
  203. If no command is given, the whole suite of tests is run.
  204. """
  205. }
  206. cmd_args = opt.opts.init(opts_data)
  207. if opt.system: sys.path.pop(0)
  208. if opt.buf_keypress:
  209. send_delay = 0.3
  210. else:
  211. send_delay = 0
  212. os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
  213. if opt.debug: opt.verbose = True
  214. if opt.exact_output:
  215. def msg(s): pass
  216. vmsg = vmsg_r = msg_r = msg
  217. else:
  218. def msg(s): sys.stderr.write(s+"\n")
  219. def vmsg(s):
  220. if opt.verbose: sys.stderr.write(s+"\n")
  221. def msg_r(s): sys.stderr.write(s)
  222. def vmsg_r(s):
  223. if opt.verbose: sys.stderr.write(s)
  224. stderr_save = sys.stderr
  225. def silence():
  226. if not (opt.verbose or opt.exact_output):
  227. sys.stderr = open("/dev/null","a")
  228. def end_silence():
  229. if not (opt.verbose or opt.exact_output):
  230. sys.stderr = stderr_save
  231. def errmsg(s): stderr_save.write(s+"\n")
  232. def errmsg_r(s): stderr_save.write(s)
  233. if opt.list_cmds:
  234. fs = " {:<{w}} - {}"
  235. Msg("Available commands:")
  236. w = max([len(i) for i in cmd_data])
  237. for cmd in cmd_data:
  238. Msg(fs.format(cmd,cmd_data[cmd][1],w=w))
  239. Msg("\nAvailable metacommands:")
  240. w = max([len(i) for i in meta_cmds])
  241. for cmd in meta_cmds:
  242. Msg(fs.format(cmd," + ".join(meta_cmds[cmd][1]),w=w))
  243. Msg("\nAvailable utilities:")
  244. w = max([len(i) for i in utils])
  245. for cmd in sorted(utils):
  246. Msg(fs.format(cmd,utils[cmd],w=w))
  247. sys.exit()
  248. import pexpect,time,re
  249. from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file
  250. def my_send(p,t,delay=send_delay,s=False):
  251. if delay: time.sleep(delay)
  252. ret = p.send(t) # returns num bytes written
  253. if delay: time.sleep(delay)
  254. if opt.verbose:
  255. ls = "" if opt.debug or not s else " "
  256. es = "" if s else " "
  257. msg("%sSEND %s%s" % (ls,es,yellow("'%s'"%t.replace('\n',r'\n'))))
  258. return ret
  259. def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
  260. quo = "'" if type(s) == str else ""
  261. if opt.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo))
  262. else: msg_r("+")
  263. try:
  264. if s == '': ret = 0
  265. else:
  266. f = p.expect if regex else p.expect_exact
  267. ret = f(s,timeout=3)
  268. except pexpect.TIMEOUT:
  269. errmsg(red("\nERROR. Expect %s%s%s timed out. Exiting" % (quo,s,quo)))
  270. sys.exit(1)
  271. if opt.debug or (opt.verbose and type(s) != str): msg_r(" ==> %s " % ret)
  272. if ret == -1:
  273. errmsg("Error. Expect returned %s" % ret)
  274. sys.exit(1)
  275. else:
  276. if t == '':
  277. if not nonl: vmsg("")
  278. else: ret = my_send(p,t,delay,s)
  279. return ret
  280. def get_file_with_ext(ext,mydir,delete=True):
  281. flist = [os.path.join(mydir,f) for f in os.listdir(mydir)
  282. if f == ext or f[-(len(ext)+1):] == "."+ext]
  283. if not flist: return False
  284. if len(flist) > 1:
  285. if delete:
  286. if not opt.quiet:
  287. msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
  288. for f in flist: os.unlink(f)
  289. return False
  290. else:
  291. return flist[0]
  292. def get_addrfile_checksum(display=False):
  293. addrfile = get_file_with_ext("addrs",cfg['tmpdir'])
  294. silence()
  295. from mmgen.addr import AddrInfo
  296. chk = AddrInfo(addrfile).checksum
  297. if opt.verbose and display: msg("Checksum: %s" % cyan(chk))
  298. end_silence()
  299. return chk
  300. def verify_checksum_or_exit(checksum,chk):
  301. if checksum != chk:
  302. errmsg(red("Checksum error: %s" % chk))
  303. sys.exit(1)
  304. vmsg(green("Checksums match: %s") % (cyan(chk)))
  305. class MMGenExpect(object):
  306. def __init__(self,name,mmgen_cmd,cmd_args=[]):
  307. if not opt.system:
  308. mmgen_cmd = os.path.join(os.curdir,mmgen_cmd)
  309. desc = cmd_data[name][1]
  310. if opt.verbose or opt.exact_output:
  311. sys.stderr.write(
  312. green("Testing %s\nExecuting " % desc) +
  313. cyan("'%s %s'\n" % (mmgen_cmd," ".join(cmd_args)))
  314. )
  315. else:
  316. msg_r("Testing %s " % (desc+":"))
  317. if opt.direct_exec:
  318. os.system(" ".join([mmgen_cmd] + cmd_args))
  319. sys.exit()
  320. else:
  321. self.p = pexpect.spawn(mmgen_cmd,cmd_args)
  322. if opt.exact_output: self.p.logfile = sys.stdout
  323. def license(self):
  324. p = "'w' for conditions and warranty info, or 'c' to continue: "
  325. my_expect(self.p,p,'c')
  326. def usr_rand(self,num_chars):
  327. rand_chars = list(getrandstr(num_chars,no_space=True))
  328. my_expect(self.p,'symbols left: ','x')
  329. try:
  330. vmsg_r("SEND ")
  331. while self.p.expect('left: ',0.1) == 0:
  332. ch = rand_chars.pop(0)
  333. msg_r(yellow(ch)+" " if opt.verbose else "+")
  334. self.p.send(ch)
  335. except:
  336. vmsg("EOT")
  337. my_expect(self.p,"ENTER to continue: ",'\n')
  338. def passphrase_new(self,what,passphrase):
  339. my_expect(self.p,("Enter passphrase for %s: " % what), passphrase+"\n")
  340. my_expect(self.p,"Repeat passphrase: ", passphrase+"\n")
  341. def passphrase(self,what,passphrase,pwtype=""):
  342. if pwtype: pwtype += " "
  343. my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,what)),
  344. passphrase+"\n",regex=True)
  345. def hash_preset(self,what,preset=''):
  346. my_expect(self.p,("Enter hash preset for %s, or ENTER .*?:" % what),
  347. str(preset)+"\n",regex=True)
  348. def written_to_file(self,what,overwrite_unlikely=False,query="Overwrite? "):
  349. s1 = "%s written to file " % what
  350. s2 = query + "Type uppercase 'YES' to confirm: "
  351. ret = my_expect(self.p,s1 if overwrite_unlikely else [s1,s2])
  352. if ret == 1:
  353. my_send(self.p,"YES\n")
  354. ret = my_expect(self.p,s1)
  355. outfile = self.p.readline().strip().strip("'")
  356. vmsg("%s file: %s" % (what,cyan(outfile.replace("'",""))))
  357. return outfile
  358. def no_overwrite(self):
  359. self.expect("Overwrite? Type uppercase 'YES' to confirm: ","\n")
  360. self.expect("Exiting at user request")
  361. def tx_view(self):
  362. my_expect(self.p,r"View .*?transaction.*? \(y\)es, \(N\)o, pager \(v\)iew.*?: ","\n",regex=True)
  363. def expect_getend(self,s,regex=False):
  364. ret = self.expect(s,regex=regex,nonl=True)
  365. end = self.readline().strip()
  366. vmsg(" ==> %s" % cyan(end))
  367. return end
  368. def interactive(self):
  369. return self.p.interact()
  370. def logfile(self,arg):
  371. self.p.logfile = arg
  372. def expect(self,*args,**kwargs):
  373. return my_expect(self.p,*args,**kwargs)
  374. def send(self,*args,**kwargs):
  375. return my_send(self.p,*args,**kwargs)
  376. def readline(self):
  377. return self.p.readline()
  378. def readlines(self):
  379. return [l.rstrip()+"\n" for l in self.p.readlines()]
  380. def read(self,n=None):
  381. return self.p.read(n)
  382. from mmgen.rpc.data import TransactionInfo
  383. from decimal import Decimal
  384. from mmgen.bitcoin import verify_addr
  385. def add_fake_unspent_entry(out,address,comment):
  386. out.append(TransactionInfo(
  387. account = unicode(comment),
  388. vout = int(getrandnum(4) % 8),
  389. txid = unicode(hexlify(os.urandom(32))),
  390. amount = Decimal("%s.%s" % (10+(getrandnum(4) % 40), getrandnum(4) % 100000000)),
  391. address = address,
  392. spendable = False,
  393. scriptPubKey = ("76a914"+verify_addr(address,return_hex=True)+"88ac"),
  394. confirmations = getrandnum(4) % 500
  395. ))
  396. def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input=''):
  397. out = []
  398. for s in tx_data.keys():
  399. sid = tx_data[s]['sid']
  400. a = adata.addrinfo(sid)
  401. for idx,btcaddr in a.addrpairs():
  402. add_fake_unspent_entry(out,btcaddr,"%s:%s Test Wallet" % (sid,idx))
  403. if non_mmgen_input:
  404. from mmgen.bitcoin import privnum2addr,hextowif
  405. privnum = getrandnum(32)
  406. btcaddr = privnum2addr(privnum,compressed=True)
  407. of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
  408. write_to_file(of, hextowif("{:064x}".format(privnum),
  409. compressed=True)+"\n","compressed bitcoin key")
  410. add_fake_unspent_entry(out,btcaddr,"Non-MMGen address")
  411. # msg("\n".join([repr(o) for o in out])); sys.exit()
  412. write_to_file(unspent_data_file,repr(out),"Unspent outputs",verbose=True)
  413. def add_comments_to_addr_file(addrfile,tfile):
  414. silence()
  415. msg(green("Adding comments to address file '%s'" % addrfile))
  416. from mmgen.addr import AddrInfo
  417. a = AddrInfo(addrfile)
  418. for i in a.idxs(): a.set_comment(idx,"Test address %s" % idx)
  419. write_to_file(tfile,a.fmt_data(),{})
  420. end_silence()
  421. def make_brainwallet_file(fn):
  422. # Print random words with random whitespace in between
  423. from mmgen.mn_tirosh import tirosh_words
  424. wl = tirosh_words.split("\n")
  425. nwords,ws_list,max_spaces = 10," \n",5
  426. def rand_ws_seq():
  427. nchars = getrandnum(1) % max_spaces + 1
  428. return "".join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)])
  429. rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)]
  430. d = "".join(rand_pairs).rstrip() + "\n"
  431. if opt.verbose: msg_r("Brainwallet password:\n%s" % cyan(d))
  432. write_to_file(fn,d,"brainwallet password")
  433. def do_between():
  434. if opt.pause:
  435. from mmgen.util import keypress_confirm
  436. if keypress_confirm(green("Continue?"),default_yes=True):
  437. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  438. else:
  439. errmsg("Exiting at user request")
  440. sys.exit()
  441. elif opt.verbose or opt.exact_output:
  442. sys.stderr.write("\n")
  443. hincog_bytes = 1024*1024
  444. hincog_offset = 98765
  445. hincog_seedlen = 256
  446. rebuild_list = OrderedDict()
  447. def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False):
  448. rerun = True if root else False # force_delete is not passed to recursive call
  449. fns = []
  450. if force_delete or not root:
  451. ret = ts.get_num_exts_for_cmd(cmd,dpy) #does cmd produce a needed dependency?
  452. if ret:
  453. for ext in ret[1]:
  454. fn = get_file_with_ext(ext,cfgs[ret[0]]['tmpdir'],delete=build)
  455. if fn:
  456. if force_delete: os.unlink(fn)
  457. else: fns.append(fn)
  458. else: rerun = True
  459. fdeps = ts.generate_file_deps(cmd)
  460. cdeps = ts.generate_cmd_deps(fdeps)
  461. for fn in fns:
  462. my_age = os.stat(fn).st_mtime
  463. for num,ext in fdeps:
  464. f = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
  465. if f and os.stat(f).st_mtime > my_age: rerun = True
  466. for cdep in cdeps:
  467. if check_needs_rerun(ts,cdep,build=build,root=False,dpy=cmd): rerun = True
  468. if build:
  469. if rerun:
  470. for fn in fns:
  471. if not root: os.unlink(fn)
  472. ts.do_cmd(cmd)
  473. if not root: do_between()
  474. else:
  475. # If prog produces multiple files:
  476. if cmd not in rebuild_list or rerun == True:
  477. rebuild_list[cmd] = (rerun,fns[0] if fns else "") # FIX
  478. return rerun
  479. def refcheck(what,chk,refchk):
  480. vmsg("Comparing %s '%s' to stored reference" % (what,chk))
  481. if chk == refchk:
  482. ok()
  483. else:
  484. if not opt.verbose: errmsg("")
  485. errmsg(red("""
  486. Fatal error - %s '%s' does not match reference value '%s'. Aborting test
  487. """.strip() % (what,chk,refchk)))
  488. sys.exit(3)
  489. def check_deps(ts,name,cmds):
  490. if len(cmds) != 1:
  491. msg("Usage: %s check_deps <command>" % g.prog_name)
  492. sys.exit(1)
  493. cmd = cmds[0]
  494. if cmd not in cmd_data:
  495. msg("'%s': unrecognized command" % cmd)
  496. sys.exit(1)
  497. if not opt.quiet:
  498. msg("Checking dependencies for '%s'" % (cmd))
  499. check_needs_rerun(ts,cmd,build=False)
  500. w = max(len(i) for i in rebuild_list) + 1
  501. for cmd in rebuild_list:
  502. c = rebuild_list[cmd]
  503. m = "Rebuild" if (c[0] and c[1]) else "Build" if c[0] else "OK"
  504. msg("cmd {:<{w}} {}".format(cmd+":", m, w=w))
  505. # msgrepr(cmd,c)
  506. def clean(dirs=[]):
  507. ts = MMGenTestSuite()
  508. dirlist = ts.list_tmp_dirs()
  509. if not dirs: dirs = dirlist.keys()
  510. for d in sorted(dirs):
  511. if d in dirlist:
  512. cleandir(dirlist[d])
  513. else:
  514. msg("%s: invalid directory number" % d)
  515. sys.exit(1)
  516. class MMGenTestSuite(object):
  517. def __init__(self):
  518. pass
  519. def list_tmp_dirs(self):
  520. d = {}
  521. for k in cfgs: d[k] = cfgs[k]['tmpdir']
  522. return d
  523. def get_num_exts_for_cmd(self,cmd,dpy=False): # dpy ignored here
  524. num = str(cmd_data[cmd][0])
  525. dgl = cfgs[num]['dep_generators']
  526. # msgrepr(num,cmd,dgl)
  527. if cmd in dgl.values():
  528. ext = [k for k in dgl if dgl[k] == cmd][0]
  529. return (num,[ext])
  530. else:
  531. return None
  532. def do_cmd(self,cmd):
  533. d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
  534. al = [get_file_with_ext(ext,cfgs[num]['tmpdir']) for num,ext in d]
  535. global cfg
  536. cfg = cfgs[str(cmd_data[cmd][0])]
  537. self.__class__.__dict__[cmd](*([self,cmd] + al))
  538. def generate_file_deps(self,cmd):
  539. return [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
  540. def generate_cmd_deps(self,fdeps):
  541. return [cfgs[str(n)]['dep_generators'][ext] for n,ext in fdeps]
  542. def walletgen(self,name,brain=False):
  543. args = ["-d",cfg['tmpdir'],"-p1","-r10"]
  544. # if 'seed_len' in cfg: args += ["-l",cfg['seed_len']]
  545. if brain:
  546. bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename'])
  547. args += ["-b",cfg['bw_params'],bwf]
  548. make_brainwallet_file(bwf)
  549. t = MMGenExpect(name,"mmgen-walletgen", args)
  550. t.license()
  551. if brain:
  552. t.expect(
  553. "A brainwallet will be secure only if you really know what you're doing")
  554. t.expect("Type uppercase 'YES' to confirm: ","YES\n")
  555. t.usr_rand(10)
  556. for s in "user-supplied entropy","saved user-supplied entropy":
  557. t.expect("Generating encryption key from OS random data plus %s" % s)
  558. if brain: break
  559. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  560. t.written_to_file("Wallet")
  561. ok()
  562. def refwalletgen(self,name):
  563. args = ["-q","-d",cfg['tmpdir'],"-p1","-r10","-b"+cfg['bw_hashparams']]
  564. t = MMGenExpect(name,"mmgen-walletgen", args)
  565. t.expect("passphrase: ",cfg['bw_passwd']+"\n")
  566. t.usr_rand(10)
  567. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  568. key_id = t.written_to_file("Wallet").split("-")[0].split("/")[-1]
  569. refcheck("key id",key_id,cfg['key_id'])
  570. def passchg(self,name,walletfile):
  571. t = MMGenExpect(name,"mmgen-passchg",
  572. ["-d",cfg['tmpdir'],"-p","2","-L","New Label","-r","16",walletfile])
  573. t.passphrase("MMGen wallet",cfgs['1']['wpasswd'],pwtype="old")
  574. t.expect_getend("Label changed: ")
  575. t.expect_getend("Hash preset has changed ")
  576. t.passphrase("MMGen wallet",cfg['wpasswd'],pwtype="new")
  577. t.expect("Repeat passphrase: ",cfg['wpasswd']+"\n")
  578. t.usr_rand(16)
  579. t.expect_getend("Key ID changed: ")
  580. t.written_to_file("Wallet")
  581. ok()
  582. def walletchk_newpass(self,name,walletfile):
  583. t = self.walletchk_beg(name,[walletfile])
  584. ok()
  585. def walletchk_beg(self,name,args):
  586. t = MMGenExpect(name,"mmgen-walletchk", args)
  587. t.expect("Getting MMGen wallet data from file '%s'" % args[-1])
  588. t.passphrase("MMGen wallet",cfg['wpasswd'])
  589. t.expect("Passphrase is OK")
  590. t.expect("Wallet is OK")
  591. return t
  592. def walletchk(self,name,walletfile):
  593. t = self.walletchk_beg(name,[walletfile])
  594. ok()
  595. def addrgen(self,name,walletfile,check_ref=False):
  596. t = MMGenExpect(name,"mmgen-addrgen",["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  597. t.license()
  598. t.passphrase("MMGen wallet",cfg['wpasswd'])
  599. t.expect("Passphrase is OK")
  600. t.expect("[0-9]+ addresses generated",regex=True)
  601. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  602. if check_ref:
  603. refcheck("address data checksum",chk,cfg['addrfile_chk'])
  604. return
  605. t.written_to_file("Addresses")
  606. ok()
  607. def refaddrgen(self,name,walletfile):
  608. self.addrgen(name,walletfile,check_ref=True)
  609. def addrimport(self,name,addrfile):
  610. outfile = os.path.join(cfg['tmpdir'],"addrfile_w_comments")
  611. add_comments_to_addr_file(addrfile,outfile)
  612. t = MMGenExpect(name,"mmgen-addrimport",[outfile])
  613. t.expect_getend(r"checksum for addr data .*\[.*\]: ",regex=True)
  614. t.expect_getend("Validating addresses...OK. ")
  615. t.expect("Type uppercase 'YES' to confirm: ","\n")
  616. vmsg("This is a simulation, so no addresses were actually imported into the tracking\nwallet")
  617. ok()
  618. def txcreate(self,name,addrfile):
  619. self.txcreate_common(name,sources=['1'])
  620. def txcreate_common(self,name,sources=['1'],non_mmgen_input=''):
  621. if opt.verbose or opt.exact_output:
  622. sys.stderr.write(green("Generating fake transaction info\n"))
  623. silence()
  624. from mmgen.addr import AddrInfo,AddrInfoList
  625. tx_data,ail = {},AddrInfoList()
  626. from mmgen.util import parse_addr_idxs
  627. for s in sources:
  628. afile = get_file_with_ext("addrs",cfgs[s]["tmpdir"])
  629. ai = AddrInfo(afile)
  630. ail.add(ai)
  631. aix = parse_addr_idxs(cfgs[s]['addr_idx_list'])
  632. if len(aix) != addrs_per_wallet:
  633. errmsg(red("Addr index list length != %s: %s" %
  634. (addrs_per_wallet,repr(aix))))
  635. sys.exit()
  636. tx_data[s] = {
  637. 'addrfile': afile,
  638. 'chk': ai.checksum,
  639. 'sid': ai.seed_id,
  640. 'addr_idxs': aix[-2:],
  641. }
  642. unspent_data_file = os.path.join(cfg['tmpdir'],"unspent.json")
  643. create_fake_unspent_data(ail,unspent_data_file,tx_data,non_mmgen_input)
  644. # make the command line
  645. from mmgen.bitcoin import privnum2addr
  646. btcaddr = privnum2addr(getrandnum(32),compressed=True)
  647. cmd_args = ["-d",cfg['tmpdir']]
  648. for num in tx_data.keys():
  649. s = tx_data[num]
  650. cmd_args += [
  651. "%s:%s,%s" % (s['sid'],s['addr_idxs'][0],cfgs[num]['amts'][0]),
  652. ]
  653. # + one BTC address
  654. # + one change address and one BTC address
  655. if num is tx_data.keys()[-1]:
  656. cmd_args += ["%s:%s" % (s['sid'],s['addr_idxs'][1])]
  657. cmd_args += ["%s,%s" % (btcaddr,cfgs[num]['amts'][1])]
  658. for num in tx_data: cmd_args += [tx_data[num]['addrfile']]
  659. os.environ["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file
  660. end_silence()
  661. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  662. t = MMGenExpect(name,"mmgen-txcreate",cmd_args)
  663. t.license()
  664. for num in tx_data.keys():
  665. t.expect_getend("Getting address data from file ")
  666. chk=t.expect_getend(r"Computed checksum for addr data .*?: ",regex=True)
  667. verify_checksum_or_exit(tx_data[num]['chk'],chk)
  668. # not in tracking wallet warning, (1 + num sources) times
  669. if t.expect(["Continue anyway? (y/N): ",
  670. "Unable to connect to bitcoind"]) == 0:
  671. t.send("y")
  672. else:
  673. errmsg(red("Error: unable to connect to bitcoind. Exiting"))
  674. sys.exit(1)
  675. for num in tx_data.keys():
  676. t.expect("Continue anyway? (y/N): ","y")
  677. t.expect(r"'q' = quit sorting, .*?: ","M", regex=True)
  678. t.expect(r"'q' = quit sorting, .*?: ","q", regex=True)
  679. outputs_list = [addrs_per_wallet*i + 1 for i in range(len(tx_data))]
  680. if non_mmgen_input: outputs_list.append(len(tx_data)*addrs_per_wallet + 1)
  681. t.expect("Enter a range or space-separated list of outputs to spend: ",
  682. " ".join([str(i) for i in outputs_list])+"\n")
  683. if non_mmgen_input: t.expect("Accept? (y/N): ","y")
  684. t.expect("OK? (Y/n): ","y")
  685. t.expect("Add a comment to transaction? (y/N): ","\n")
  686. t.tx_view()
  687. t.expect("Save transaction? (y/N): ","y")
  688. t.written_to_file("Transaction")
  689. ok()
  690. def txsign(self,name,txfile,walletfile):
  691. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txfile,walletfile])
  692. t.license()
  693. t.tx_view()
  694. t.passphrase("MMGen wallet",cfg['wpasswd'])
  695. t.expect("Edit transaction comment? (y/N): ","\n")
  696. t.written_to_file("Signed transaction")
  697. ok()
  698. def txsend(self,name,sigfile):
  699. t = MMGenExpect(name,"mmgen-txsend", ["-d",cfg['tmpdir'],sigfile])
  700. t.license()
  701. t.tx_view()
  702. t.expect("Edit transaction comment? (y/N): ","\n")
  703. t.expect("Are you sure you want to broadcast this transaction to the network?")
  704. t.expect("Type uppercase 'YES, I REALLY WANT TO DO THIS' to confirm: ","\n")
  705. t.expect("Exiting at user request")
  706. vmsg("This is a simulation, so no transaction was sent")
  707. ok()
  708. def export_seed(self,name,walletfile):
  709. t = self.walletchk_beg(name,["-s","-d",cfg['tmpdir'],walletfile])
  710. f = t.written_to_file("Seed data")
  711. silence()
  712. msg("Seed data: %s" % cyan(get_data_from_file(f,"seed data")))
  713. end_silence()
  714. ok()
  715. def export_mnemonic(self,name,walletfile):
  716. t = self.walletchk_beg(name,["-m","-d",cfg['tmpdir'],walletfile])
  717. f = t.written_to_file("Mnemonic data")
  718. silence()
  719. msg_r("Mnemonic data: %s" % cyan(get_data_from_file(f,"mnemonic data")))
  720. end_silence()
  721. ok()
  722. def export_incog(self,name,walletfile,args=["-g"]):
  723. t = MMGenExpect(name,"mmgen-walletchk",args+["-d",cfg['tmpdir'],"-r","10",walletfile])
  724. t.passphrase("MMGen wallet",cfg['wpasswd'])
  725. t.usr_rand(10)
  726. t.expect_getend("Incog ID: ")
  727. if args[0] == "-G": return t
  728. t.written_to_file("Incognito wallet data",overwrite_unlikely=True)
  729. ok()
  730. def export_incog_hex(self,name,walletfile):
  731. self.export_incog(name,walletfile,args=["-X"])
  732. # TODO: make outdir and hidden incog compatible (ignore --outdir and warn user?)
  733. def export_incog_hidden(self,name,walletfile):
  734. rf,rd = os.path.join(cfg['tmpdir'],hincog_fn),os.urandom(hincog_bytes)
  735. vmsg(green("Writing %s bytes of data to file '%s'" % (hincog_bytes,rf)))
  736. write_to_file(rf,rd,verbose=opt.verbose)
  737. t = self.export_incog(name,walletfile,args=["-G","%s,%s"%(rf,hincog_offset)])
  738. t.written_to_file("Data",query="")
  739. ok()
  740. def addrgen_seed(self,name,walletfile,foo,what="seed data",arg="-s"):
  741. t = MMGenExpect(name,"mmgen-addrgen",
  742. [arg,"-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  743. t.license()
  744. t.expect_getend("Valid %s for seed ID " % what)
  745. vmsg("Comparing generated checksum with checksum from previous address file")
  746. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  747. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  748. t.no_overwrite()
  749. ok()
  750. def addrgen_mnemonic(self,name,walletfile,foo):
  751. self.addrgen_seed(name,walletfile,foo,what="mnemonic",arg="-m")
  752. def addrgen_incog(self,name,walletfile,foo,args=["-g"]):
  753. t = MMGenExpect(name,"mmgen-addrgen",args+["-d",
  754. cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  755. t.license()
  756. t.expect_getend("Incog ID: ")
  757. t.passphrase("MMGen incognito wallet \w{8}", cfg['wpasswd'])
  758. t.hash_preset("incog wallet",'1')
  759. vmsg("Comparing generated checksum with checksum from address file")
  760. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  761. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  762. t.no_overwrite()
  763. ok()
  764. def addrgen_incog_hex(self,name,walletfile,foo):
  765. self.addrgen_incog(name,walletfile,foo,args=["-X"])
  766. def addrgen_incog_hidden(self,name,walletfile,foo):
  767. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  768. self.addrgen_incog(name,walletfile,foo,
  769. args=["-G","%s,%s,%s"%(rf,hincog_offset,hincog_seedlen)])
  770. def keyaddrgen(self,name,walletfile,check_ref=False):
  771. t = MMGenExpect(name,"mmgen-keygen",
  772. ["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  773. t.license()
  774. t.expect("Type uppercase 'YES' to confirm: ","YES\n")
  775. t.passphrase("MMGen wallet",cfg['wpasswd'])
  776. chk = t.expect_getend(r"Checksum for key-address data .*?: ",regex=True)
  777. if check_ref:
  778. refcheck("key-address data checksum",chk,cfg['keyaddrfile_chk'])
  779. return
  780. t.expect("Encrypt key list? (y/N): ","y")
  781. t.hash_preset("new key list",'1')
  782. t.passphrase_new("new key list",cfg['kapasswd'])
  783. t.written_to_file("Keys")
  784. ok()
  785. def refkeyaddrgen(self,name,walletfile):
  786. self.keyaddrgen(name,walletfile,check_ref=True)
  787. def txsign_keyaddr(self,name,keyaddr_file,txfile):
  788. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],"-M",keyaddr_file,txfile])
  789. t.license()
  790. t.hash_preset("key-address file",'1')
  791. t.passphrase("key-address file",cfg['kapasswd'])
  792. t.expect("Check key-to-address validity? (y/N): ","y")
  793. t.tx_view()
  794. t.expect("Signing transaction...OK")
  795. t.expect("Edit transaction comment? (y/N): ","\n")
  796. t.written_to_file("Signed transaction")
  797. ok()
  798. def walletgen2(self,name):
  799. self.walletgen(name)
  800. def addrgen2(self,name,walletfile):
  801. self.addrgen(name,walletfile)
  802. def txcreate2(self,name,addrfile):
  803. self.txcreate_common(name,sources=['2'])
  804. def txsign2(self,name,txf1,wf1,txf2,wf2):
  805. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txf1,wf1,txf2,wf2])
  806. t.license()
  807. for cnum in ['1','2']:
  808. t.tx_view()
  809. t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd'])
  810. t.expect_getend("Signing transaction ")
  811. t.expect("Edit transaction comment? (y/N): ","\n")
  812. t.written_to_file("Signed transaction #%s" % cnum)
  813. ok()
  814. def export_mnemonic2(self,name,walletfile):
  815. self.export_mnemonic(name,walletfile)
  816. def walletgen3(self,name):
  817. self.walletgen(name)
  818. def addrgen3(self,name,walletfile):
  819. self.addrgen(name,walletfile)
  820. def txcreate3(self,name,addrfile1,addrfile2):
  821. self.txcreate_common(name,sources=['1','3'])
  822. def txsign3(self,name,wf1,wf2,txf2):
  823. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],wf1,wf2,txf2])
  824. t.license()
  825. t.tx_view()
  826. for s in ['1','3']:
  827. t.expect_getend("Getting MMGen wallet data from file ")
  828. t.passphrase("MMGen wallet",cfgs[s]['wpasswd'])
  829. t.expect_getend("Signing transaction")
  830. t.expect("Edit transaction comment? (y/N): ","\n")
  831. t.written_to_file("Signed transaction")
  832. ok()
  833. def walletgen4(self,name):
  834. self.walletgen(name,brain=True)
  835. def addrgen4(self,name,walletfile):
  836. self.addrgen(name,walletfile)
  837. def txcreate4(self,name,f1,f2,f3,f4):
  838. self.txcreate_common(name,sources=['1','2','3','4'],non_mmgen_input='4')
  839. def txsign4(self,name,f1,f2,f3,f4,f5):
  840. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  841. t = MMGenExpect(name,"mmgen-txsign",
  842. ["-d",cfg['tmpdir'],"-b",cfg['bw_params'],"-k",non_mm_fn,f1,f2,f3,f4,f5])
  843. t.license()
  844. t.tx_view()
  845. for cfgnum,what,app in ('1',"incognito"," incognito"),('3',"MMGen",""):
  846. t.expect_getend("Getting %s wallet data from file " % what)
  847. t.passphrase("MMGen%s wallet"%app,cfgs[cfgnum]['wpasswd'])
  848. if cfgnum == '1':
  849. t.hash_preset("incog wallet",'1')
  850. t.expect_getend("Signing transaction")
  851. t.expect("Edit transaction comment? (y/N): ","\n")
  852. t.written_to_file("Signed transaction")
  853. ok()
  854. def tool_encrypt(self,name,infile=""):
  855. if infile:
  856. infn = infile
  857. else:
  858. d = os.urandom(1033)
  859. tmp_fn = cfg['tool_enc_infn']
  860. write_to_tmpfile(cfg,tmp_fn,d)
  861. infn = get_tmpfile_fn(cfg,tmp_fn)
  862. t = MMGenExpect(name,"mmgen-tool",["-d",cfg['tmpdir'],"encrypt",infn])
  863. t.hash_preset("user data",'1')
  864. t.passphrase_new("user data",cfg['tool_enc_passwd'])
  865. t.written_to_file("Encrypted data")
  866. ok()
  867. def tool_encrypt_ref(self,name):
  868. infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn'])
  869. write_to_file(infn,cfg['tool_enc_reftext'],silent=True)
  870. self.tool_encrypt(name,infn)
  871. # Two deps produced by one prog is broken - TODO
  872. def tool_decrypt(self,name,f1,f2):
  873. of = name + ".out"
  874. t = MMGenExpect(name,"mmgen-tool",
  875. ["-d",cfg['tmpdir'],"decrypt",f2,"outfile="+of,"hash_preset=1"])
  876. t.passphrase("user data",cfg['tool_enc_passwd'])
  877. t.written_to_file("Decrypted data")
  878. d1 = read_from_file(f1)
  879. d2 = read_from_file(get_tmpfile_fn(cfg,of))
  880. cmp_or_die(d1,d2)
  881. def tool_decrypt_ref(self,name,f1,f2):
  882. self.tool_decrypt(name,f1,f2)
  883. # main()
  884. if opt.pause:
  885. import termios,atexit
  886. fd = sys.stdin.fileno()
  887. old = termios.tcgetattr(fd)
  888. def at_exit():
  889. termios.tcsetattr(fd, termios.TCSADRAIN, old)
  890. atexit.register(at_exit)
  891. start_time = int(time.time())
  892. ts = MMGenTestSuite()
  893. for cfg in sorted(cfgs): mk_tmpdir(cfgs[cfg])
  894. try:
  895. if cmd_args:
  896. arg1 = cmd_args[0]
  897. if arg1 in utils:
  898. globals()[arg1](cmd_args[1:])
  899. sys.exit()
  900. elif arg1 in meta_cmds:
  901. if len(cmd_args) == 1:
  902. for cmd in meta_cmds[arg1][1]:
  903. check_needs_rerun(ts,cmd,build=True,force_delete=True)
  904. else:
  905. msg("Only one meta command may be specified")
  906. sys.exit(1)
  907. elif arg1 in cmd_data.keys():
  908. if len(cmd_args) == 1:
  909. check_needs_rerun(ts,arg1,build=True)
  910. else:
  911. msg("Only one command may be specified")
  912. sys.exit(1)
  913. else:
  914. errmsg("%s: unrecognized command" % arg1)
  915. sys.exit(1)
  916. else:
  917. clean()
  918. for cmd in cmd_data:
  919. ts.do_cmd(cmd)
  920. if cmd is not cmd_data.keys()[-1]: do_between()
  921. except:
  922. sys.stderr = stderr_save
  923. raise
  924. t = int(time.time()) - start_time
  925. msg(green(
  926. "All requested tests finished OK, elapsed time: %02i:%02i" % (t/60,t%60)))