def main(apps=None, network="main", keystore_cls=None): """ apps: list of apps to load network: default network to operate keystores: list of KeyStore classes that can be used """ # create virtual file system /sdram # for temp untrusted data storage rampath = platform.mount_sdram() # define hosts - USB, QR, SDCard # each hosts gets it's own RAM folder for data hosts = [ QRHost(rampath + "/qr"), USBHost(rampath + "/usb"), # SDHost(rampath+"/sd"), # not implemented yet ] # temp storage in RAM for host commands processing BaseApp.TEMPDIR = rampath+"/tmp" # define GUI gui = SpecterGUI() # inject the folder where keystore stores it's data KeyStore.path = platform.fpath("/flash/keystore") # detect keystore to use if keystore_cls is not None: keystores = [keystore_cls] else: keystores = [ MemoryCard, SDKeyStore, ] # loading apps if apps is None: apps = load_apps() # make Specter instance settings_path = platform.fpath("/flash") specter = Specter( gui=gui, keystores=keystores, hosts=hosts, apps=apps, settings_path=settings_path, network=network, ) specter.start()
def load_apps(module='apps', whitelist=None, blacklist=None): mod = __import__(module) mods = mod.__all__ apps = [] if blacklist is not None: mods = [mod for mod in mods if mod not in blacklist] if whitelist is not None: mods = [mod for mod in mods if mod in whitelist] for modname in mods: appmod = __import__('%s.%s' % (module, modname)) mod = getattr(appmod, modname) if hasattr(mod, 'App'): app = mod.App(platform.fpath("/qspi/%s" % modname)) apps.append(app) else: print("Failed loading app:", modname) return apps
async def export_menu(self, show_screen): while True: buttons = [ (None, "Export options"), (1, "Show QR code"), (2, "Save to SD card", platform.is_sd_present()), ] menuitem = await show_screen( Menu(buttons, last=(255, None), title="Export wallet %s" % self.name)) desc = add_checksum(str(self.descriptor.branch(0))) obj = { "descriptor": desc, "label": self.name, } if self.descriptor.num_branches > 2: obj["branches"] = [ add_checksum(str(self.descriptor.branch(i))) for i in range(self.descriptor.num_branches) ] if menuitem == 1: await show_screen( QRAlert( title="Export wallet %s" % self.name, qr_width=450, message= "Scan this QR code with compatible software wallet", qr_message=json.dumps(obj))) elif menuitem == 2: if not platform.is_sd_present(): raise WalletError("SD card is not present") platform.mount_sdcard() fname = "/sd/%s.json" % self.name with open(platform.fpath(fname), "w") as f: json.dump(obj, f) platform.unmount_sdcard() await show_screen( Alert("Success!", "Wallet descriptor is written to\n\n%s" % fname)) else: return
async def setup(self): try: path = fpath("/flash/KEYSTORECLS") # check if the user already selected the keystore class if self.keystore is None: await self.select_keystore(path) if self.keystore is not None: self.load_network(self.path, self.network) # load secrets await self.keystore.init(self.gui.show_screen()) if not file_exists(path): # save selected keystore with open(path, "w") as f: f.write(self.keystore.__class__.__name__) # unlock with PIN or set up the PIN code await self.unlock() except Exception as e: next_fn = await self.handle_exception(e, self.setup) await next_fn() await self.main()
def load_config(self): try: config, _ = self.keystore.load_aead(self.path+"/settings", self.keystore.enc_secret) config = json.loads(config.decode()) except Exception as e: print(e) config = {"dev": self.dev, "usb": self.usb} self.keystore.save_aead(self.path+"/settings", adata=json.dumps(config).encode(), key=self.keystore.enc_secret) self.dev = config["dev"] self.usb = config["usb"] # add apps in dev mode if self.dev: try: qspi = fpath("/qspi/extensions") maybe_mkdir(qspi) maybe_mkdir(qspi+"/extra_apps") if qspi not in sys.path: sys.path.append(qspi) self.apps += load_apps('extra_apps') except Exception as e: print(e)
def wipe(self): # TODO: wipe the smartcard as well? delete_recursively(fpath("/flash")) delete_recursively(fpath("/qspi"))
def __init__(self, path, sdpath=fpath("/sd")): super().__init__(path) self.sdpath = sdpath self.f = None self.fram = self.path + "/data" self.sd_file = self.sdpath + "/signed.psbt"
def sdpath(self): hexid = hexlify(tagged_hash("sdid", self.secret)[:4]).decode() return platform.fpath("/sd/specterdiy%s" % hexid)
def sdpath(self): return platform.fpath("/sd")
def __init__(self, path, sdpath=fpath("/sd")): super().__init__(path) self.sdpath = sdpath
def main(apps=None, network="main", keystore_cls=None): """ apps: list of apps to load network: default network to operate keystores: list of KeyStore classes that can be used """ # Init display first as it also inits the SDRAM display.init(False) # create virtual file system /sdram # for temp untrusted data storage rampath = platform.mount_sdram() # set working path to empty folder in sdram if not platform.simulator: cwd = rampath + "/cwd" platform.maybe_mkdir(cwd) os.chdir(cwd) # define hosts - USB, QR, SDCard # each hosts gets it's own RAM folder for data Host.SETTINGS_DIR = platform.fpath("/qspi/hosts") Specter.SETTINGS_DIR = platform.fpath("/qspi/global") hosts = [ USBHost(rampath + "/usb"), QRHost(rampath + "/qr"), SDHost(rampath + "/sd"), ] # temp storage in RAM for host commands processing BaseApp.TEMPDIR = rampath + "/tmp" # define GUI if not platform.simulator: gui = SpecterGUI() else: # this GUI can simulate user actions for automated testing from gui.tcp_gui import TCPGUI gui = TCPGUI() # inject the folder where keystore stores it's data KeyStore.path = platform.fpath("/flash/keystore") # detect keystore to use if keystore_cls is not None: keystores = [keystore_cls] else: keystores = [ MemoryCard, SDKeyStore, ] # loading apps if apps is None: apps = load_apps() # make Specter instance settings_path = platform.fpath("/flash") specter = Specter( gui=gui, keystores=keystores, hosts=hosts, apps=apps, settings_path=settings_path, network=network, ) specter.start()