示例#1
0
    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
示例#2
0
    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
示例#3
0
    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()
示例#4
0
    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
示例#5
0
 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
示例#8
0
    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
示例#9
0
    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
示例#11
0
    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
示例#14
0
    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()
示例#15
0
    def get_redeem_scripts():
        settings = Settings.Instance().get_settings_json()
        if 'redeemScripts' not in settings:
            return None

        return settings["redeemScripts"]