diff --git a/src/seedsigner/models/psbt_parser.py b/src/seedsigner/models/psbt_parser.py index 6f1260998..769fb1e46 100644 --- a/src/seedsigner/models/psbt_parser.py +++ b/src/seedsigner/models/psbt_parser.py @@ -35,6 +35,7 @@ def __init__(self, p: PSBT, seed: Seed, network: str = SettingsConstants.MAINNET self.destination_addresses = [] self.destination_amounts = [] self.op_return_data: bytes = None + self.dnssec_proof: str = None self.root = None @@ -119,6 +120,8 @@ def _parse_outputs(self): self.fee_amount = 0 self.destination_addresses = [] self.destination_amounts = [] + self.dnssec_proof = None + for i, out in enumerate(self.psbt.outputs): out_policy = PSBTParser._get_policy(out, self.psbt.tx.vout[i].script_pubkey, self.psbt.xpubs) is_change = False @@ -223,6 +226,9 @@ def _parse_outputs(self): self.destination_amounts.append(self.psbt.tx.vout[i].value) self.spend_amount += self.psbt.tx.vout[i].value + if out.dnssec_proof: + self.dnssec_proof = out.dnssec_proof + self.fee_amount = self.psbt.fee() return True diff --git a/src/seedsigner/views/psbt_views.py b/src/seedsigner/views/psbt_views.py index 1cd09d1e5..fae6f1179 100644 --- a/src/seedsigner/views/psbt_views.py +++ b/src/seedsigner/views/psbt_views.py @@ -133,7 +133,7 @@ def run(self): # Everything is set. Stop the loading screen if self.loading_screen: self.loading_screen.stop() - + # Run the overview screen selected_menu_num = self.run_screen( PSBTOverviewScreen, @@ -160,6 +160,7 @@ def run(self): return Destination(PSBTNoChangeWarningView) else: + if psbt_parser.dnssec_proof: return Destination(PSBTDnsNameView) return Destination(PSBTMathView) @@ -206,6 +207,38 @@ def run(self): +class PSBTDnsNameView(View): + def run(self): + from seedsigner.gui.screens.screen import LargeIconStatusScreen + from embit.bip353 import verify_dns_proof + + psbt_parser: PSBTParser = self.controller.psbt_parser + if not psbt_parser: + # Should not be able to get here + return Destination(MainMenuView) + + dnssec_data = psbt_parser.dnssec_proof + dns_name = dnssec_data[0].decode('utf-8').replace('@', '.user._bitcoin-payment.') + proof = dnssec_data[1] + + verified = verify_dns_proof(dns_name+'.', proof) + if not 'error' in verified and len(verified['verified_rrs']) > 0: # Check if there is a valid record for that name in the proof + selected_menu_num = LargeIconStatusScreen( + title = _("DNS name verification"), + button_data = [ButtonOption("Review math")], + text = _("Verification complete. Review the DNS name."), + status_headline = dns_name, + ).display() + else: + return Destination(PSBTDnsNameErrorView) + + if selected_menu_num == RET_CODE__BACK_BUTTON: + return Destination(BackStackView) + else: + return Destination(PSBTMathView) + + + class PSBTMathView(View): """ Follows the Overview pictogram. Shows: @@ -597,3 +630,32 @@ def run(self): if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) + + + +class PSBTDnsNameErrorView(View): + SELECT_DIFF_SEED = ButtonOption("Return") + + def run(self): + psbt_parser: PSBTParser = self.controller.psbt_parser + if not psbt_parser: + # Should not be able to get here + return Destination(MainMenuView) + + # Just a WarningScreen here; only use DireWarningScreen for true security risks. + selected_menu_num = self.run_screen( + WarningScreen, + title=_("DNS name Error"), + status_icon_name=SeedSignerIconConstants.WARNING, + status_headline=_("DENSSEC verification Failed"), + text=_("Verification not compelted. Verify the DNS name and the proof."), + button_data=[self.SELECT_DIFF_SEED] + ) + + if selected_menu_num == 0: + # clear seed selected for psbt signing since it did not add a valid signature + self.controller.psbt_seed = None + return Destination(MainMenuView, clear_history=True) + + if selected_menu_num == RET_CODE__BACK_BUTTON: + return Destination(MainMenuView) \ No newline at end of file diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index e45373fcb..89d855002 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -296,6 +296,37 @@ def PSBTOpReturnView_raw_hex_data_cb_before(): controller.psbt_parser = PSBTParser(p=controller.psbt, seed=seed_12b) + def PSBTaddDNSSECproof(): + controller.psbt_parser.dnssec_proof = (b'craig@sparrowwallet.com', + b'\x00\x00.\x00\x01\x00\x00@r\x01\x13\x000\x08\x00\x00\x02\xa3\x00h\xa6a\x80h\x8a\xb2\x00Of\x00}\x11K\xf3>m \xe7X\x8f\xdf\xde\x9a\x9e*\x8e\xbdU\x93\xce\x8b\xc0d\x19\xe1\xd1\xa4\xaf\xa8vj\xbc\x16&PN\xa6$<\xa5\xfc\x9b\xceU\xa3\xf0<\x0e~\xb4\x88@\x96\x90\xd8L;\xeb0\xf2\x99\xda\x00z\xb6\x92\x99\xd0\xe2\x03\xc5\xb4K\x942\x82Hv\x80\x89\xa9 \ + \xb6\x89\x82e\x0e\x9c\xa2\xd3u&0|\xbd\x9f\x06i\x0eX\xc3\xc4\xa1p;\x1d\x11\x93\xea\x05\x01AyD\xb97\xb5\x93)N3\x95q\xee\xc4*
\xcb\x8dW5\xb92\x1d\xb0\x85\xf1\xb8\xe2\xd8\x03 \
+ \x8f\xe2\x94\x19\x92T\x8c\xee\rg\xddEG\xe1\x1d\xd6:\xf9\xc9\xfc\x1cTf\xfbhL\xf0\t\xd7\x19|,\xf7\x9ey*\xb5\x01\xe6\xa8\xa1\xcaQ\x9a\xf2\xcb\x9b_cg\xe9L\rGP$Q5{\xe1\xb5\x00\x000\x00\x01\x00\x00@r\x01\x08\x01\x01\x03\x08\x03\x01\x00\x01\xafz\x8d\xeb\xa4\x9d\x99Zy*\xef\xc8\x02c\xe9\x91\xef\xdb\xc8a8\xa91\xde\xb2\xc6]V\x82\xea\xb5\xd3\xb078\xe3\xdf \
+ \xdc\x89\xd9m\xa6L\x86\xc0"M\x9c\xe0%\x14\xd2\x85\xda0h\xb1\x90T\xe5\xe7\x87\xb2\x96\x90X\xe9\x8e\x12Vl\x8c\x80\x8c@\xc0\xb7i\xe1\xdb\x1a$\xa1\xbd\x9b1\xe3\x03\x18J1\xfc{\xb5k\x85\xbb\xba\x8a\xbc\x02\xcdP@\xa4D\xa3mGiYi\x84\x9e\x16\xad\x85k\xb5\x8e\x8f\xac\x88U"D\x001\x9b\xda\xb2$\xd8?\xc0\xe6j\xab2\xfft\xbf\xea\xf0\xf9\x1cENhP\xa1)R\x07\xbb\xd4 \
+ \xcd\xde\x8fo\xfb\x08\xfa\xa9u\\.2\x84\xef\xa0\x1f\x999>\x18xl\xb12\xf1\xe6n\xbce\x171\x8e\x1c\xe8\xa3\xb73~\xbbT\xd05\xabW\xd9pn\xcd\x93P\xd4\xaf\xac\xd8%\xe4<\x86h\xee\xce\x89\x81\x9c\xafh\x17\xafb\xdcO\xbd\x82\xf0\xe3?fG\xb2\xb6\xbd\xa1u\xf1F\x07\xf5\x9fF5E\x1ek\'\xdf(.\xf7=\x87\x03com\x00\x00+\x00\x01\x00\x00\xb0R\x00$M\x06\r\x02\x8a\xcb\xb0 \
+ \xcd(\xf4\x12P\xa8\nI\x13\x89BM4\x15"\xd9F\xb0\xda\x0c\x02\x91\xf2\xd3\xd7q\xd7\x80Z\x03com\x00\x00.\x00\x01\x00\x00\xb0R\x01\x13\x00+\x08\x01\x00\x01Q\x80h\x9c\xfc\xd0h\x8b\xcb@\xb5i\x00\x92\xd8;\xb6#\x9d\x1b\xa6\xde\xd5\x9bO~\xe5/,\x15\x94\x8eO\x86\xc9\x9d\xdc\xd93\x16p\x99|\xbc\xd9\xbc\xa2\xab\x88%\x18\xb3\x8b~\xdf\xce\x82\x02/\xdcj\x0e\xde\x88Q} \
+ \rL\xddp\x0b\xa8a:\xa9\xc0*\xee\xd6\x8c\xdb\xab\xe1LZ\x8c\n\xb2d\xcb\xb07P\xca\xd1\xd4\xcco\xb9\x83G\xf4\x98\x9b\xd7cc\xe8\xa0\xe4D\x96\x94@\xa0\x08;\x9c\xe6>Eau\xb0\n\xa1\xaeR\t\x96\x0b\xe2\xb1N \xec\xf4v\x17A\xe9\x80\xbf\xa0-\xd8\xc4*gh\xd1\xa3\xc2\xd4\x1e&\x86\x10L40Q\xe3_\x91\xdf\xdb9Xi!\x04\xe4\xcc\x0e:\xb1\x9f\x08\xf9\x88\x1d\xb4)1\xa7\xb7*\xa9 \
+ \x9ahT\x8e\xbd[E\xa4\x17\xe7\x81\x84A\xe3\x18,b\xbf\x94\xce\x8f\x189\x85P\x9d}r\xd7-\xcc\xcf\xd8\x0cm\x85\x17\x9e:\xbc\x03\xc3-\xe8\xc4\xd5-w\x02\xda\xdf-\xe0;co\x89\xb694\xba\xe6\xca-AWZ\xd3\xfd\xa4\xe4\x8e]\xee\xac\xe4N\x17\xab\x19\x03com\x00\x00.\x00\x01\x00\x00\x19\xb8\x00W\x000\r\x01\x00\x01Q\x80h\x9f=\xfbh\x8bvOM\x06\x03com\x00\xd8ss\xf3\xd5\xd4 \
+ \x04\xf7\xcd\xc3\xaa\xcec<\x965{\xc6\x06\xce\xd6 y%\x97\xe10\x8b\x1dlY\x02f\x8cM<\x1a7\xba\xb8Hk\xa2D\x85\xd5z\x9d\x98\x15\x7f\xe7\x06BK C\xbf\xb4\x03\x06\xd0\x14\x84\x03com\x00\x000\x00\x01\x00\x00\x19\xb8\x00D\x01\x00\x03\r\xf1{`\xfbV\xd5"\xf8cAS\xe7\x85\xc0\xa9xS.\xa7m\xe3\x9d4\xbb5m=\x04.\x07\xf2\x9f{\x99!v\xcc\x83\xac\xef{x\xeau\x04% ;\x18\xf2\xb8" \
+ \x8b<\xdd+\xc7\xeb\x13\xc3\xe3\x03Z~\x03com\x00\x000\x00\x01\x00\x00\x19\xb8\x00D\x01\x01\x03\r\xb7\x1f\x04e\x10\x1d\xdb\xe2\xbf\x0c\x94U\xd1/\xa1l\x1c\xdaD\xf4\xbf\x1b\xa2U4\x18\xad\x1f:\xa9\xb0is\xf2\x1b\x84\xebS,\xf4\x03^\xe8\xd4\x83,\xa2m\x890j}2V\x0c\x0c\xb0\x12\x9dE\n\xc1\x085\rsparrowwallet\x03com\x00\x00+\x00\x01\x00\x00T_\x00$=\xc4\r\x02V\x04\r \
+ \x99\x1c\x10u\xc4\xa8UTE\xf9\xa5\xceR\xceh\x01\xaa\xf4]>\x87f>\x7f\xbdh\xbc1+\rsparrowwallet\x03com\x00\x00+\x00\x01\x00\x00T_\x00$\xcf;\r\x02em\xa5\x986B/^\x19\x8es\xfc5\xe6\xa8\x9b\xc0\x83\x8d\xea\xacV^q\xa1\x98\x04\xfc\x12P\xe4\xce\rsparrowwallet\x03com\x00\x00.\x00\x01\x00\x00T_\x00W\x00+\r\x02\x00\x01Q\x80h\x95a\x02h\x8c\x16\x1aPA\x03com\x00\xf4\xc4 \
+ \nX5#\xa7\xd4%P_2\x8a\xfe\x10\xe8\x16\xed\xe3\xf01\xd1Wr\xd87i\xec\x84\x90\xd0\x82\x16r\xe4\xee\xfbu\xfb\x0b\xe4\xff\xe8g\x15\xfb\xec)l\x109\x03h\xb3\x12\x08 \xcb\x8dW5\xb92\x1d\xb0\x85\xf1\xb8\xe2\xd8\x03\x8f\xe2\x94\x19\x92T\x8c\xee\rg\xddEG\xe1\x1d\xd6:\xf9\xc9\xfc\x1cTf\xfbhL\xf0\t\xd7\x19|,\xf7\x9ey*\xb5\x01\xe6\xa8\xa1\xcaQ\x9a\xf2\xcb\x9b_cg\xe9L\rGP$Q5{\xe1\xb5\x00\x000\x00\x01\x00\x00#r\x01\x08\x01\x01\x03\x08\x03\x01\x00\x01\xafz\x8d\xeb\xa4\x9d\x99Zy*\xef\xc8\x02c\xe9\x91\xef\xdb\xc8a8\xa91\xde\xb2\xc6]V\x82\xea\xb5\xd3\xb078\xe3\xdf\xdc\x89\xd9m\xa6L\x86\xc0"M\x9c\xe0%\x14\xd2\x85\xda0h\xb1\x90T\xe5\xe7\x87\xb2\x96\x90X\xe9\x8e\x12Vl\x8c\x80\x8c@\xc0\xb7i\xe1\xdb\x1a$\xa1\xbd\x9b1\xe3\x03\x18J1\xfc{\xb5k\x85\xbb\xba\x8a\xbc\x02\xcdP@\xa4D\xa3mGiYi\x84\x9e\x16\xad\x85k\xb5\x8e\x8f\xac\x88U"D\x001\x9b\xda\xb2$\xd8?\xc0\xe6j\xab2\xfft\xbf\xea\xf0\xf9\x1cENhP\xa1)R\x07\xbb\xd4\xcd\xde\x8fo\xfb\x08\xfa\xa9u\\.2\x84\xef\xa0\x1f\x999>\x18xl\xb12\xf1\xe6n\xbce\x171\x8e\x1c\xe8\xa3\xb73~\xbbT\xd05\xabW\xd9pn\xcd\x93P\xd4\xaf\xac\xd8%\xe4<\x86h\xee\xce\x89\x81\x9c\xafh\x17\xafb\xdcO\xbd\x82\xf0\xe3?fG\xb2\xb6\xbd\xa1u\xf1F\x07\xf5\x9fF5E\x1ek\'\xdf(.\xf7=\x87\x03com\x00\x00+\x00\x01\x00\x00\xb0R\x00$M\x06\r\x02\x8a\xcb\xb0\xcd(\xf4\x12P\xa8\nI\x13\x89BM4\x15"\xd9F\xb0\xda\x0c\x02\x91\xf2\xd3\xd7q\xd7\x80Z\x03com\x00\x00.\x00\x01\x00\x00\xb0R\x01\x13\x00+\x08\x01\x00\x01Q\x80h\x9c\xfc\xd0h\x8b\xcb@\xb5i\x00\x92\xd8;\xb6#\x9d\x1b\xa6\xde\xd5\x9bO~\xe5/,\x15\x94\x8eO\x86\xc9\x9d\xdc\xd93\x16p\x99|\xbc\xd9\xbc\xa2\xab\x88%\x18\xb3\x8b~\xdf\xce\x82\x02/\xdcj\x0e\xde\x88Q}\rL\xddp\x0b\xa8a:\xa9\xc0*\xee\xd6\x8c\xdb\xab\xe1LZ\x8c\n\xb2d\xcb\xb07P\xca\xd1\xd4\xcco\xb9\x83G\xf4\x98\x9b\xd7cc\xe8\xa0\xe4D\x96\x94@\xa0\x08;\x9c\xe6>Eau\xb0\n\xa1\xaeR\t\x96\x0b\xe2\xb1N \xec\xf4v\x17A\xe9\x80\xbf\xa0-\xd8\xc4*gh\xd1\xa3\xc2\xd4\x1e&\x86\x10L40Q\xe3_\x91\xdf\xdb9Xi!\x04\xe4\xcc\x0e:\xb1\x9f\x08\xf9\x88\x1d\xb4)1\xa7\xb7*\xa9\x9ahT\x8e\xbd[E\xa4\x17\xe7\x81\x84A\xe3\x18,b\xbf\x94\xce\x8f\x189\x85P\x9d}r\xd7-\xcc\xcf\xd8\x0cm\x85\x17\x9e:\xbc\x03\xc3-\xe8\xc4\xd5-w\x02\xda\xdf-\xe0;co\x89\xb694\xba\xe6\xca-AWZ\xd3\xfd\xa4\xe4\x8e]\xee\xac\xe4N\x17\xab\x19\x03com\x00\x00.\x00\x01\x00\x00\x19\xb8\x00W\x000\r\x01\x00\x01Q\x80h\x9f=\xfbh\x8bvOM\x06\x03com\x00\xd8ss\xf3\xd5\xd4\x04\xf7\xcd\xc3\xaa\xcec<\x965{\xc6\x06\xce\xd6 y%\x97\xe10\x8b\x1dlY\x02f\x8cM<\x1a7\xba\xb8Hk\xa2D\x85\xd5z\x9d\x98\x15\x7f\xe7\x06BK C\xbf\xb4\x03\x06\xd0\x14\x84\x03com\x00\x000\x00\x01\x00\x00\x19\xb8\x00D\x01\x00\x03\r\xf1{`\xfbV\xd5"\xf8cAS\xe7\x85\xc0\xa9xS.\xa7m\xe3\x9d4\xbb5m=\x04.\x07\xf2\x9f{\x99!v\xcc\x83\xac\xef{x\xeau\x04% ;\x18\xf2\xb8"\x8b<\xdd+\xc7\xeb\x13\xc3\xe3\x03Z~\x03com\x00\x000\x00\x01\x00\x00\x19\xb8\x00D\x01\x01\x03\r\xb7\x1f\x04e\x10\x1d\xdb\xe2\xbf\x0c\x94U\xd1/\xa1l\x1c\xdaD\xf4\xbf\x1b\xa2U4\x18\xad\x1f:\xa9\xb0is\xf2\x1b\x84\xebS,\xf4\x03^\xe8\xd4\x83,\xa2m\x890j}2V\x0c\x0c\xb0\x12\x9dE\n\xc1\x085\rsparrowwallet\x03com\x00\x00+\x00\x01\x00\x00T_\x00$=\xc4\r\x02V\x04\r\x99\x1c\x10u\xc4\xa8UTE\xf9\xa5\xceR\xceh\x01\xaa\xf4]>\x87f>\x7f\xbdh\xbc1+\rsparrowwallet\x03com\x00\x00+\x00\x01\x00\x00T_\x00$\xcf;\r\x02em\xa5\x986B/^\x19\x8es\xfc5\xe6\xa8\x9b\xc0\x83\x8d\xea\xacV^q\xa1\x98\x04\xfc\x12P\xe4\xce\rsparrowwallet\x03com\x00\x00.\x00\x01\x00\x00T_\x00W\x00+\r\x02\x00\x01Q\x80h\x95a\x02h\x8c\x16\x1aPA\x03com\x00\xf4\xc4\nX5#\xa7\xd4%P_2\x8a\xfe\x10\xe8\x16\xed\xe3\xf01\xd1Wr\xd87i\xec\x84\x90\xd0\x82\x16r\xe4\xee\xfbu\xfb\x0b\xe4\xff\xe8g\x15\xfb\xec)l\x109\x03h\xb3\x12\x08