def __init__(self, dev=False, usb=False): super().__init__("Developer and USB", "") usb_label = add_label("USB communication", 120, scr=self.page) usb_hint = add_label("If USB is enabled the device will be able " "to talk to your computer. This increases " "attack surface but sometimes makes it " "more convenient to use.", 160, scr=self.page, style="hint") self.usb_switch = lv.sw(self.page) self.usb_switch.align(usb_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label( " OFF ON ", scr=self.page) lbl.align(self.usb_switch, lv.ALIGN.CENTER, 0, 0) if usb: self.usb_switch.on(lv.ANIM.OFF) dev_label = add_label("Developer mode", 320, scr=self.page) dev_hint = add_label("In developer mode internal flash will " "be mounted to your computer so you could " "edit files, but your secrets will be visible as well. " "Also enables interactive shell through miniUSB port.", 360, scr=self.page, style="hint") self.dev_switch = lv.sw(self.page) self.dev_switch.align(dev_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label( " OFF ON ", scr=self.page) lbl.align(self.dev_switch, lv.ALIGN.CENTER, 0, 0) if dev: self.dev_switch.on(lv.ANIM.OFF) self.confirm_button.set_event_cb(on_release(self.update)) self.cancel_button.set_event_cb( on_release(lambda: self.set_value(None)))
def show_settings(config, save_callback): def cb(): new_config = { "usb": usb_switch.get_state(), "developer": dev_switch.get_state() } save_callback(new_config) scr = Prompt("Device settings", "", confirm_callback=cb) scr.confirm_label.set_text("Save & Reboot") usb_label = add_label("USB communication", 120, scr=scr) usb_hint = add_label( "If USB is enabled the device will be able to talk to your computer. This increases attack surface but sometimes makes it more convenient to use.", 160, scr=scr, style="hint") usb_switch = lv.sw(scr) usb_switch.align(usb_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label(" OFF ON ") lbl.align(usb_switch, lv.ALIGN.CENTER, 0, 0) if config["usb"]: usb_switch.on(lv.ANIM.OFF) dev_label = add_label("Developer mode", 320, scr=scr) dev_hint = add_label( "In developer mode internal flash will be mounted to your computer so you could edit files, but your secrets will be visible as well. Also enables interactive shell through miniUSB port.", 360, scr=scr, style="hint") dev_switch = lv.sw(scr) dev_switch.align(dev_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label(" OFF ON ") lbl.align(dev_switch, lv.ALIGN.CENTER, 0, 0) if config["developer"]: dev_switch.on(lv.ANIM.OFF)
def __init__(self, dev=False, usb=False): super().__init__("Developer and USB", "") y = 70 usb_label = add_label("USB communication", y, scr=self.page) usb_hint = add_label( "If USB is enabled the device will be able " "to talk to your computer. This increases " "attack surface but sometimes makes it " "more convenient to use.", y + 40, scr=self.page, style="hint", ) self.usb_switch = lv.sw(self.page) self.usb_switch.align(usb_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label(" OFF ON ", scr=self.page) lbl.align(self.usb_switch, lv.ALIGN.CENTER, 0, 0) if usb: self.usb_switch.on(lv.ANIM.OFF) y += 200 dev_label = add_label("Developer mode", y, scr=self.page) dev_hint = add_label( "In developer mode internal flash will " "be mounted to your computer so you could " "edit files, but your secrets will be visible as well. " "Also enables interactive shell through miniUSB port.", y + 40, scr=self.page, style="hint", ) self.dev_switch = lv.sw(self.page) self.dev_switch.align(dev_hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 20) lbl = add_label(" OFF ON ", scr=self.page) lbl.align(self.dev_switch, lv.ALIGN.CENTER, 0, 0) if dev: self.dev_switch.on(lv.ANIM.OFF) self.confirm_button.set_event_cb(on_release(self.update)) self.cancel_button.set_event_cb(on_release(lambda: self.set_value(None))) self.wipebtn = add_button( lv.SYMBOL.TRASH + " Wipe device", on_release(self.wipe), scr=self ) self.wipebtn.align(self, lv.ALIGN.IN_BOTTOM_MID, 0, -140) style = lv.style_t() lv.style_copy(style, self.wipebtn.get_style(lv.btn.STYLE.REL)) style.body.main_color = lv.color_hex(0x951E2D) style.body.grad_color = lv.color_hex(0x951E2D) self.wipebtn.set_style(lv.btn.STYLE.REL, style)
def __init__(self, generator, title="Your recovery phrase:", note="Write it down and never show to anybody"): mnemonic = generator(12) super().__init__(mnemonic, title, note) self.table.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 50) self.close_label.set_text(lv.SYMBOL.LEFT+" Back") self.next_button = add_button(scr=self, callback=on_release(self.confirm)) self.next_label = lv.label(self.next_button) self.next_label.set_text("Next "+lv.SYMBOL.RIGHT) align_button_pair(self.close_button, self.next_button) lbl = lv.label(self) lbl.set_text("Use 24 words") lbl.align(self.table, lv.ALIGN.OUT_BOTTOM_MID, 0, 60) lbl.set_x(120) self.switch = lv.sw(self) self.switch.off(lv.ANIM.OFF) self.switch.align(lbl, lv.ALIGN.OUT_RIGHT_MID, 20, 0) def cb(): wordcount = 24 if self.switch.get_state() else 12 self.table.set_mnemonic(generator(wordcount)) self.switch.set_event_cb(on_release(cb))
def __init__(self, controls, title="Host setttings", note=None): super().__init__(title, "") y = 40 if note is not None: self.note = add_label(note, style="hint", scr=self) self.note.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 5) y += self.note.get_height() self.controls = controls self.switches = [] for control in controls: label = add_label(control["label"], y, scr=self.page) hint = add_label( control.get("hint", ""), y + 30, scr=self.page, style="hint", ) switch = lv.sw(self.page) switch.align(hint, lv.ALIGN.OUT_BOTTOM_MID, 0, 10) lbl = add_label(" OFF ON ", scr=self.page) lbl.align(switch, lv.ALIGN.CENTER, 0, 0) if control.get("value", False): switch.on(lv.ANIM.OFF) self.switches.append(switch) y = lbl.get_y() + 80 self.confirm_button.set_event_cb(on_release(self.update)) self.cancel_button.set_event_cb( on_release(lambda: self.set_value(None)))
def __init__( self, xpub, slip132=None, prefix=None, title="Your master public key", qr_width=None, button_text="Close", sd=True, ): message = xpub if slip132 is not None: message = slip132 if prefix is not None: message = prefix + message super().__init__(title, message, message, qr_width=320) self.message.set_style(0, styles["small"]) self.xpub = xpub self.prefix = prefix self.slip132 = slip132 if prefix is not None: lbl = lv.label(self) lbl.set_text("Show derivation path") lbl.set_pos(2 * PADDING, 500) self.prefix_switch = lv.sw(self) self.prefix_switch.on(lv.ANIM.OFF) self.prefix_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) if slip132 is not None: lbl = lv.label(self) lbl.set_text("Use SLIP-132") lbl.set_pos(2 * PADDING, 560) self.slip_switch = lv.sw(self) self.slip_switch.on(lv.ANIM.OFF) self.slip_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) if prefix is not None: self.prefix_switch.set_event_cb(on_release(self.toggle_event)) if slip132 is not None: self.slip_switch.set_event_cb(on_release(self.toggle_event)) if sd: btn = add_button("Save to SD card", on_release(self.save_to_sd), y=610, scr=self)
def __init__( self, generator, wordlist, fixer, title="Your recovery phrase:", note="Write it down and never show it to anybody.", ): self.fixer = fixer self.wordlist = wordlist mnemonic = generator(12) super().__init__(mnemonic, title, note) self.table.align(self.title, lv.ALIGN.OUT_BOTTOM_MID, 0, 50) self.table.set_event_cb(self.on_word_click) # enable callbacks self.table.set_click(True) self.close_label.set_text(lv.SYMBOL.LEFT + " Back") self.done_button = add_button(scr=self, callback=on_release(self.confirm)) self.done_label = lv.label(self.done_button) self.done_label.set_text(lv.SYMBOL.OK + " Done") align_button_pair(self.close_button, self.done_button) # toggle switch 12-24 words lbl = lv.label(self) lbl.set_text("Use 24 words") lbl.align(self.table, lv.ALIGN.OUT_BOTTOM_MID, 0, 40) lbl.set_x(120) self.switch_lbl = lbl self.switch = lv.sw(self) self.switch.off(lv.ANIM.OFF) self.switch.align(lbl, lv.ALIGN.OUT_RIGHT_MID, 20, 0) def cb(): wordcount = 24 if self.switch.get_state() else 12 self.table.set_mnemonic(generator(wordcount)) self.switch.set_event_cb(on_release(cb)) # fix mnemonic components self.kb = lv.btnm(self) self.kb.set_map([ "1", "2", "4", "8", "16", "32", "\n", "64", "128", "256", "512", "1024", "" ]) self.kb.set_ctrl_map([lv.btnm.CTRL.TGL_ENABLE for i in range(11)]) self.kb.set_width(HOR_RES) self.kb.set_height(100) self.kb.align(self.table, lv.ALIGN.OUT_BOTTOM_MID, 0, 5) self.kb.set_hidden(True) self.instruction = add_label( "Hint: click on any word above to edit it.", scr=self, style="hint") self.instruction.align(self.kb, lv.ALIGN.OUT_BOTTOM_MID, 0, 15)
def show_xpub(name, xpub, slip132=None, prefix=None, callback=None): if slip132 is not None: msg = slip132 else: msg = xpub if prefix is not None: msg = prefix+msg scr = qr_alert(name, msg, msg, callback) style = lv.style_t() lv.style_copy(style, scr.message.get_style(0)) style.text.font = lv.font_roboto_mono_22 scr.message.set_style(0, style) if prefix is not None: lbl = lv.label(scr) lbl.set_text("Show derivation path") lbl.set_pos(2*PADDING, 590) prefix_switch = lv.sw(scr) prefix_switch.on(lv.ANIM.OFF) prefix_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) if slip132 is not None: lbl = lv.label(scr) lbl.set_text("Use SLIP-132") lbl.set_pos(2*PADDING, 640) slip_switch = lv.sw(scr) slip_switch.on(lv.ANIM.OFF) slip_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) def cb(): msg = xpub if slip132 is not None and slip_switch.get_state(): msg = slip132 if prefix is not None and prefix_switch.get_state(): msg = prefix+msg scr.message.set_text(msg) scr.qr.set_text(msg) if prefix is not None: prefix_switch.set_event_cb(on_release(cb)) if slip132 is not None: slip_switch.set_event_cb(on_release(cb))
def __init__( self, xpub, slip132=None, prefix=None, title="Your master public key", qr_width=None, button_text="Close", ): message = xpub if slip132 is not None: message = slip132 if prefix is not None: message = prefix + message super().__init__(title, message, message) self.xpub = xpub self.prefix = prefix self.slip132 = slip132 if prefix is not None: lbl = lv.label(self) lbl.set_text("Show derivation path") lbl.set_pos(2 * PADDING, 580) self.prefix_switch = lv.sw(self) self.prefix_switch.on(lv.ANIM.OFF) self.prefix_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) if slip132 is not None: lbl = lv.label(self) lbl.set_text("Use SLIP-132") lbl.set_pos(2 * PADDING, 640) self.slip_switch = lv.sw(self) self.slip_switch.on(lv.ANIM.OFF) self.slip_switch.align(lbl, lv.ALIGN.OUT_LEFT_MID, 350, 0) if prefix is not None: self.prefix_switch.set_event_cb(on_release(self.toggle_event)) if slip132 is not None: self.slip_switch.set_event_cb(on_release(self.toggle_event))
def __init__(self, name, policy, keys): super().__init__('Add wallet "%s"?' % name, "") self.policy = add_label("Policy: " + policy, y=75, scr=self) lbl = lv.label(self) lbl.set_text( "Canonical xpub SLIP-132 ") lbl.align(self.policy, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) self.slip_switch = lv.sw(self) self.slip_switch.align(lbl, lv.ALIGN.CENTER, 0, 0) self.slip_switch.set_event_cb(on_release(self.fill_message)) self.page.align(self.policy, lv.ALIGN.OUT_BOTTOM_MID, 0, 70) self.message.set_recolor(True) self.page.set_height(500) self.keys = keys self.fill_message()
def __init__(self, title, meta): send_amount = sum( [out["value"] for out in meta["outputs"] if not out["change"]]) super().__init__(title, "") obj = self.message # for alignments enable_inputs = len( [k for k in meta["inputs"] if k["sighash"] != "ALL"]) > 0 lbl = add_label("Show detailed information ", scr=self) lbl.align(obj, lv.ALIGN.CENTER, 0, 0) self.details_sw = lv.sw(self) self.details_sw.align(obj, lv.ALIGN.CENTER, 130, 0) self.details_sw.set_event_cb(on_release(self.toggle_details)) if enable_inputs: self.details_sw.on(lv.ANIM.OFF) # change page a bit self.page.set_pos(0, lbl.get_y() + 20) self.page.set_size(480, 800 - 130 - lbl.get_y()) self.page2 = lv.page(self) self.page2.set_pos(self.page.get_x(), self.page.get_y()) self.page2.set_size(self.page.get_width(), self.page.get_height()) # define styles style = lv.style_t() lv.style_copy(style, self.message.get_style(0)) style.text.font = lv.font_roboto_mono_28 style_primary = lv.style_t() lv.style_copy(style_primary, self.message.get_style(0)) style_primary.text.font = lv.font_roboto_mono_22 style_secondary = lv.style_t() lv.style_copy(style_secondary, self.message.get_style(0)) style_secondary.text.color = lv.color_hex(0x999999) style_secondary.text.font = lv.font_roboto_mono_22 style_warning = lv.style_t() lv.style_copy(style_warning, self.message.get_style(0)) style_warning.text.color = lv.color_hex(0xFF9A00) self.style = style self.style_secondary = style_secondary self.style_warning = style_warning num_change_outputs = 0 for out in meta["outputs"]: # first only show destination addresses if out["change"]: num_change_outputs += 1 continue obj = self.show_output(out, obj) if send_amount > 0: fee_percent = meta["fee"] * 100 / send_amount fee_txt = "%d satoshi (%.2f%%)" % (meta["fee"], fee_percent) # back to wallet else: fee_txt = "%d satoshi" % (meta["fee"]) fee = add_label("Fee: " + fee_txt, scr=self.page) fee.set_style(0, style) fee.align(obj, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) obj = fee # warning label for address gap limit if "warnings" in meta and len(meta["warnings"]) > 0: text = "WARNING!\n" + "\n".join(meta["warnings"]) self.warning = add_label(text, scr=self.page) self.warning.set_style(0, style_warning) self.warning.align(obj, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) lbl = add_label("%d INPUTS" % len(meta["inputs"]), scr=self.page2) lbl.align(self.page2, lv.ALIGN.IN_TOP_MID, 0, 30) obj = lbl for i, inp in enumerate(meta["inputs"]): idxlbl = lv.label(self.page2) idxlbl.set_text("%d:" % i) idxlbl.align(lbl, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) idxlbl.set_x(30) lbl = lv.label(self.page2) lbl.set_long_mode(lv.label.LONG.BREAK) lbl.set_width(380) lbl.set_text("%.8f BTC from %s" % (inp["value"] / 1e8, inp["label"])) lbl.align(idxlbl, lv.ALIGN.IN_TOP_LEFT, 0, 0) lbl.set_x(60) if inp["sighash"] != "ALL": shlbl = lv.label(self.page2) shlbl.set_long_mode(lv.label.LONG.BREAK) shlbl.set_width(380) shlbl.set_text(inp["sighash"]) shlbl.align(lbl, lv.ALIGN.OUT_BOTTOM_LEFT, 0, 5) shlbl.set_x(60) shlbl.set_style(0, style_warning) lbl = shlbl obj = lbl lbl = add_label("%d OUTPUTS" % len(meta["outputs"]), scr=self.page2) lbl.align(self.page2, lv.ALIGN.IN_TOP_MID, 0, 0) lbl.set_y(obj.get_y() + obj.get_height() + 30) for i, out in enumerate(meta["outputs"]): idxlbl = lv.label(self.page2) idxlbl.set_text("%d:" % i) idxlbl.align(lbl, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) idxlbl.set_x(30) lbl = lv.label(self.page2) lbl.set_long_mode(lv.label.LONG.BREAK) lbl.set_width(380) lbl.set_text("%.8f BTC to %s" % (out["value"] / 1e8, out.get("label", ""))) lbl.align(idxlbl, lv.ALIGN.IN_TOP_LEFT, 0, 0) lbl.set_x(60) addrlbl = lv.label(self.page2) addrlbl.set_long_mode(lv.label.LONG.BREAK) addrlbl.set_width(380) addrlbl.set_text(format_addr(out["address"], words=4)) addrlbl.align(lbl, lv.ALIGN.OUT_BOTTOM_LEFT, 0, 5) addrlbl.set_x(60) if "label" in out: addrlbl.set_style(0, style_secondary) else: addrlbl.set_style(0, style_primary) lbl = addrlbl idxlbl = lv.label(self.page2) idxlbl.set_text("Fee: " + fee_txt) idxlbl.align(lbl, lv.ALIGN.OUT_BOTTOM_MID, 0, 30) idxlbl.set_x(30) self.toggle_details()
indic_style.body.grad_color = lv.color_hex(0x9fc8ef) indic_style.body.padding.left = 0 indic_style.body.padding.right = 0 indic_style.body.padding.top = 0 indic_style.body.padding.bottom = 0 lv.style_copy(knob_off_style, lv.style_pretty) knob_off_style.body.radius = 800 knob_off_style.body.shadow.width = 4 knob_off_style.body.shadow.type = lv.SHADOW.BOTTOM lv.style_copy(knob_on_style, lv.style_pretty_color) knob_on_style.body.radius = 800 knob_on_style.body.shadow.width = 4 knob_on_style.body.shadow.type = lv.SHADOW.BOTTOM # Create a switch and apply the styles sw1 = lv.sw(lv.scr_act()) sw1.set_style(lv.sw.STYLE.BG, bg_style) sw1.set_style(lv.sw.STYLE.INDIC, indic_style) sw1.set_style(lv.sw.STYLE.KNOB_ON, knob_on_style) sw1.set_style(lv.sw.STYLE.KNOB_OFF, knob_off_style) sw1.align(None, lv.ALIGN.CENTER, 0, -50) sw1.set_event_cb(event_handler) # Copy the first switch and turn it ON sw2 = lv.sw(lv.scr_act(), sw1) sw2.on(lv.ANIM.ON) sw2.align(None, lv.ALIGN.CENTER, 0, 50) sw2.set_event_cb(lambda o, e: None)