def get_next_public_key(): settings = Settings.Instance().get_settings_json() if (settings['bip32master'] is None): raise RuntimeError("Master key has not been set up yet") account_number, account_key, key_number = KeyHelper.get_account_number_and_chain( settings) return_key = bitcoin.bip32_ckd(account_key, key_number) return_key = bitcoin.bip32_extract_key(return_key) return_key = bitcoin.privtopub(return_key) #save key for later if 'keys' not in settings['accounts'][account_number]: settings['accounts'][account_number]['keys'] = [] settings['accounts'][account_number]['keys'].append( (key_number, return_key, False)) #we increment the key counter after making the key #because the chain code is 0 indexed, making the 0th key #the first one we use key_number += 1 #remember to save our new key settings['accounts'][account_number]['numKeys'] = key_number Settings.Instance().save_config_file(settings) return return_key
def get_accounts(): settings = Settings.Instance().get_settings_json() if (settings['bip32master'] is None): return None account_number = settings['accountNumber'] account_info = {} for account in settings['accounts'].keys(): account_key = settings['accounts'][account]['accountKey'] chain_length = settings['accounts'][account]['numKeys'] #make sure we have all our keys possible_keys = set(range(chain_length)) actual_keys = set([ key[0] for key in settings['accounts'][account].get('keys', []) ]) needed_keys = possible_keys - actual_keys if len(needed_keys) > 0: if 'keys' not in settings['accounts'][account]: settings['accounts'][account]['keys'] = [] KeyHelper.regenerate_keys( account_key, needed_keys, settings['accounts'][account]['keys']) #save these if we had to regenerate them Settings.Instance().save_config_file(settings) account_info[account] = settings['accounts'][account].get( 'keys', []) return account_info, account_number
def create_redeem_script_window(self, widget, callback_data=None): if (self.redeem_script_window is not None): self.redeem_script_window.present() return self.redeem_script_window = gui.RedeemScriptWindow( "Reedem Script Management", self.window, gtk.DIALOG_DESTROY_WITH_PARENT) try: RedeemScriptWindowController(self.redeem_script_window) except nacl.exceptions.CryptoError as e: diag = gtk.MessageDialog( self.signWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Invalid Password") diag.run() diag.destroy() Settings.Instance().delete_key() self.redeem_script_window.destroy() self.redeem_script_window = None return self.redeem_script_window.connect("destroy", self.key_window_destroyed) self.redeem_script_window.show()
def get_bip32_key(public_keys): settings = Settings.Instance().get_settings_json() if (settings['bip32master'] is None): return None account_number, account_key, key_number = KeyHelper.get_account_number_and_chain( settings) #see if we already have this cached, and I can just get the key fast cached = set(settings['accounts'][account_number].get(keys, [])) pub_set = set(public_keys) hits = cached & pub_set if len(hits) > 0: return KeyHelper.get_private_for_chain(account_number, hits[0][0], settings) #drat, didn't find it! at least we can only need to test the ones that #we didn't already check missed = set(range(key_number)) - set([cache[0] for cache in cached]) for i in missed: priv = bitcoin.bip32_ckd(account_key, i) priv = bitcoin.bip32_extract_key(priv) canidate = bitcoin.privtopub(priv) if (canidate in public_keys): return priv return None
def get_private_for_chain(account, key_number, settings=None): if settings is None: settings = Settings.Instance().get_settings_json() account_key = settings['accounts'][account]['accountKey'] return_key = bitcoin.bip32_ckd(account_key, key_number) return_key = bitcoin.bip32_extract_key(return_key) return return_key
def save_settings(self): #no settings to save if there is no master key if self.settingsStore['bip32master'] is None: self.changed = False return account = self.settingsWindow.accountKeyButton.get_value_as_int() self.settingsStore["accountNumber"] = account #if there is no info for this account, we have to derive the master key for it if (account not in self.settingsStore['accounts']): self.settingsStore['accounts'][account] = {} accountHardenedKey = bitcoin.bip32_ckd( self.settingsStore['bip32master'], (account + 2**31)) #we always work with the 'external' chain, since we don't support multiple chains in an account accountKey = bitcoin.bip32_ckd(accountHardenedKey, 0) self.settingsStore['accounts'][account]['accountKey'] = accountKey #update the number of keys numKeys = self.settingsWindow.numKeysEntry.get_value_as_int() self.settingsStore['accounts'][account]['numKeys'] = numKeys Settings.Instance().save_config_file(self.settingsStore) self.changed = False return
def on_backup_button_clicked(self, widget, data=None): if self.changed is True: warn = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "You have unsaved changes. Please save before doing a backup.") warn.run() warn.destroy() return True checkIfSure = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, "This will display your master keys, which would provide full access to all address in this account. Are you Sure?" ) if (checkIfSure.run() == gtk.RESPONSE_NO): checkIfSure.destroy() return True else: checkIfSure.destroy() #delete the key, so that we have to get it from them Settings.Instance().delete_key() try: settings = Settings.Instance().get_settings_json() except nacl.exceptions.CryptoError as e: error = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Invalid password!") error.run() error.destroy() return True #delete the key cache for account in settings['accounts'].values(): if 'keys' in account: del account['keys'] settings_string = json.dumps(settings, indent=4) results = gui.ResultsWindow("Backup Information") results.set_text_content(settings_string) results.run() results.destroy() return True
def get_account_number_and_chain(settings=None, account_number=None): if settings is None: settings = Settings.Instance().get_settings_json() if account_number is None: account_number = settings['accountNumber'] account_info = settings['accounts'][account_number] account_key = account_info['accountKey'] key_number = account_info['numKeys'] return account_number, account_key, key_number
def add_redeem_script(script, notes): settings = Settings.Instance().get_settings_json() if 'redeemScripts' not in settings: settings['redeemScripts'] = [] #check for correctness of redeem_script #this will raise an exception if there is a bad script KeyHelper.parse_redeem_script(script) p2shaddr = bitcoin.scriptaddr(script) #see if this is a duplicate duplicates = [ dup for dup in settings['redeemScripts'] if dup[0] == p2shaddr ] if len(duplicates) > 0: raise ValueError("%s already in redeem script list!" % p2shaddr) settings['redeemScripts'].append([p2shaddr, script, notes]) Settings.Instance().save_config_file(settings) return settings['redeemScripts']
def on_restore_button_clicked(self, widget, data=None): if self.settingsStore is not None: checkIfSure = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, "Restoring from backup will erase all current information from your current setup. Are you sure you want to do this?" ) if (checkIfSure.run() == gtk.RESPONSE_NO): checkIfSure.destroy() return True else: checkIfSure.destroy() restore_diag = gui.SignWindow("Restore from Backup") result = restore_diag.run() #If they do anything but hit the OK button, we aren't going to do it if result != gtk.RESPONSE_OK: return False backup_json = restore_diag.get_text_content() restore_diag.destroy() try: self.settingsStore = Settings.Instance().restore_backup_json( backup_json) except (nacl.exceptions.CryptoError, IOError, ValueError) as e: error = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Unable to restore backup") error.format_secondary_markup(str(e)) error.run() error.destroy() return True self.settingsWindow.backup_button.set_sensitive(True) self.update_widget_values() confirm = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "Restore of settings complete!") confirm.run() confirm.destroy() return False
def clean_settings(backup_json): clean_settings = {} new_settings = json.loads( backup_json, object_hook=lambda x: Settings.Instance().fix_account_keys(x)) if 'bip32master' not in new_settings: raise ValueError("Given JSON doesn't have master key") vbytes, depth, fingerprint, i, chaincode, key = bitcoin.bip32_deserialize( new_settings['bip32master']) if vbytes != bitcoin.PRIVATE or depth != 0 or i != 0 or fingerprint != '\x00' * 4: raise ValueError("Master key is not at top of tree and private") clean_settings['bip32master'] = new_settings['bip32master'] clean_settings['accountNumber'] = new_settings.get("accountNumber", 1) clean_settings['accounts'] = {} for account, account_info in new_settings.get('accounts', {}).items(): if 'accountKey' not in account_info: raise ValueError("Account %i has no master key" % account) vbytes, depth, fingerprint, i, chaincode, key = bitcoin.bip32_deserialize( account_info["accountKey"]) if depth != 2 or vbytes != bitcoin.PRIVATE or i != 0: raise ValueError("Account %i has invalid master key" % account) if account_info.get("numKeys", 0) < 0: raise ValueError("Account %i has invalid key count " % account) clean_settings['accounts'][account] = {} clean_settings['accounts'][account]['accountKey'] = account_info[ 'accountKey'] clean_settings['accounts'][account]['numKeys'] = account_info.get( "numKeys", 0) clean_settings['accounts'][account]['keys'] = [] KeyHelper.regenerate_keys( account_info['accountKey'], range(account_info.get("numKeys", 0)), clean_settings['accounts'][account]['keys']) #FIXME: actually check validity of imported redeemscripts clean_settings['redeemScripts'] = new_settings.get( 'redeemScripts', []) return clean_settings
def __init__(self, settingsWindow): self.settingsWindow = settingsWindow self.settingsWindow.connect_after("response", self.window_response) self.settingsWindow.connect("delete_event", self.window_delete) self.settingsWindow.masterKeyButton.connect( "clicked", self.on_master_key_button_clicked) self.settingsWindow.backup_button.connect( "clicked", self.on_backup_button_clicked) self.settingsWindow.restore_button.connect( "clicked", self.on_restore_button_clicked) self.settingsWindow.accountKeyButton.connect("value_changed", self.update_key_nums) self.settingsStore = Settings.Instance().get_settings_json() if 'bip32master' in self.settingsStore: self.update_widget_values() else: self.settingsWindow.backup_button.set_sensitive(False) self.changed = False
def window_response(self, dialog, response_id, data=None): #fake it for now if response_id == gtk.RESPONSE_CANCEL or response_id == gtk.RESPONSE_DELETE_EVENT: if (self.changed): checkIfSure = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, "You have unsaved changes, are you sure you want to close?" ) #checkIfSure.set_image( gtk.image_new_from_stock( gtk.DIALOG_WARNING ) ) if (checkIfSure.run() == gtk.RESPONSE_NO): checkIfSure.destroy() return True else: self.changed = False self.settingsWindow.destroy() self.settingsWindow = None return try: self.save_settings() except Exception as e: alert = gtk.MessageDialog( self.settingsWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Could not save settings: " + str(e)) alert.run() alert.destroy() Settings.Instance().delete_key() return if (response_id == gtk.RESPONSE_APPLY): return self.settingsWindow.destroy() self.settingsWindow = None return
def create_settings_window(self, widget, callback_data=None): if (self.settingsWindow is not None): self.settingsWindow.present() return self.settingsWindow = gui.SettingsWindow( "Settings", self.window, gtk.DIALOG_DESTROY_WITH_PARENT) try: self.settingsController = SettingsController(self.settingsWindow) except: diag = gtk.MessageDialog( self.signWindow, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "Invalid Password") diag.run() diag.destroy() Settings.Instance().delete_key() self.settingsWindow.destroy() self.settingsWindow = None return self.settingsWindow.connect("destroy", self.settings_window_destroyed) self.settingsWindow.show()
def get_redeem_scripts(): settings = Settings.Instance().get_settings_json() if 'redeemScripts' not in settings: return None return settings["redeemScripts"]