Ejemplo n.º 1
0
    def test_update_secure_config(self):
        password = "******"
        secrets_manager = ETHKeyFileSecretManger(password)
        store_password_verification(secrets_manager)
        Security.login(secrets_manager)
        binance_config = ClientConfigAdapter(
            BinanceConfigMap(binance_api_key=self.api_key, binance_api_secret=self.api_secret)
        )
        self.async_run_with_timeout(Security.wait_til_decryption_done())

        Security.update_secure_config(binance_config)
        self.reset_security()

        Security.login(secrets_manager)
        self.async_run_with_timeout(Security.wait_til_decryption_done(), timeout=2)
        binance_loaded_config = Security.decrypted_value(binance_config.connector)

        self.assertEqual(binance_config, binance_loaded_config)

        binance_config.binance_api_key = "someOtherApiKey"
        Security.update_secure_config(binance_config)
        self.reset_security()

        Security.login(secrets_manager)
        self.async_run_with_timeout(Security.wait_til_decryption_done(), timeout=2)
        binance_loaded_config = Security.decrypted_value(binance_config.connector)

        self.assertEqual(binance_config, binance_loaded_config)
 def test_new_password_process(self):
     # empty folder, new password is required
     self.assertFalse(Security.any_encryped_files())
     self.assertTrue(Security.new_password_required())
     # login will pass with any password
     result = Security.login("a")
     self.assertTrue(result)
     Security.update_secure_config("new_key", "new_value")
     self.assertTrue(os.path.exists(f"{temp_folder}encrypted_new_key.json"))
     self.assertTrue(Security.encrypted_file_exists("new_key"))
Ejemplo n.º 3
0
 async def connect_exchange(self,  # type: HummingbotApplication
                            exchange):
     self.app.clear_input()
     self.placeholder_mode = True
     self.app.hide_input = True
     if exchange == "kraken":
         self._notify("Reminder: Please ensure your Kraken API Key Nonce Window is at least 10.")
     exchange_configs = [c for c in global_config_map.values()
                         if c.key in settings.CONNECTOR_SETTINGS[exchange].config_keys and c.is_connect_key]
     to_connect = True
     if Security.encrypted_file_exists(exchange_configs[0].key):
         await Security.wait_til_decryption_done()
         api_key_config = [c for c in exchange_configs if "api_key" in c.key]
         if api_key_config:
             api_key_config = api_key_config[0]
             api_key = Security.decrypted_value(api_key_config.key)
             prompt = f"Would you like to replace your existing {exchange} API key {api_key} (Yes/No)? >>> "
         else:
             prompt = f"Would you like to replace your existing {exchange_configs[0].key} (Yes/No)? >>> "
         answer = await self.app.prompt(prompt=prompt)
         if self.app.to_stop_config:
             self.app.to_stop_config = False
             return
         if answer.lower() not in ("yes", "y"):
             to_connect = False
     if to_connect:
         for config in exchange_configs:
             await self.prompt_a_config(config)
             if self.app.to_stop_config:
                 self.app.to_stop_config = False
                 return
             Security.update_secure_config(config.key, config.value)
         api_keys = await Security.api_keys(exchange)
         network_timeout = float(global_config_map["other_commands_timeout"].value)
         try:
             err_msg = await asyncio.wait_for(
                 UserBalances.instance().add_exchange(exchange, **api_keys), network_timeout
             )
         except asyncio.TimeoutError:
             self._notify("\nA network error prevented the connection to complete. See logs for more details.")
             self.placeholder_mode = False
             self.app.hide_input = False
             self.app.change_prompt(prompt=">>> ")
             raise
         if err_msg is None:
             self._notify(f"\nYou are now connected to {exchange}.")
         else:
             self._notify(f"\nError: {err_msg}")
     self.placeholder_mode = False
     self.app.hide_input = False
     self.app.change_prompt(prompt=">>> ")
Ejemplo n.º 4
0
 async def connect_exchange(
         self,  # type: HummingbotApplication
         exchange):
     self.app.clear_input()
     self.placeholder_mode = True
     self.app.hide_input = True
     if exchange == "kraken":
         self._notify(
             "Reminder: Please ensure your Kraken API Key Nonce Window is at least 10."
         )
     exchange_configs = [
         c for c in global_config_map.values()
         if c.key in settings.CONNECTOR_SETTINGS[exchange].config_keys
         and c.is_connect_key
     ]
     to_connect = True
     if Security.encrypted_file_exists(exchange_configs[0].key):
         await Security.wait_til_decryption_done()
         api_key_config = [
             c for c in exchange_configs if "api_key" in c.key
         ][0]
         api_key = Security.decrypted_value(api_key_config.key)
         answer = await self.app.prompt(
             prompt=
             f"Would you like to replace your existing {exchange} API key "
             f"{api_key} (Yes/No)? >>> ")
         if self.app.to_stop_config:
             self.app.to_stop_config = False
             return
         if answer.lower() not in ("yes", "y"):
             to_connect = False
     if to_connect:
         for config in exchange_configs:
             await self.prompt_a_config(config)
             if self.app.to_stop_config:
                 self.app.to_stop_config = False
                 return
             Security.update_secure_config(config.key, config.value)
         api_keys = await Security.api_keys(exchange)
         err_msg = await UserBalances.instance().add_exchange(
             exchange, **api_keys)
         if err_msg is None:
             self._notify(f"\nYou are now connected to {exchange}.")
         else:
             self._notify(f"\nError: {err_msg}")
     self.placeholder_mode = False
     self.app.hide_input = False
     self.app.change_prompt(prompt=">>> ")
Ejemplo n.º 5
0
def login_prompt():
    from hummingbot.client.config.security import Security
    import time

    err_msg = None
    if Security.new_password_required():
        show_welcome()
        password = input_dialog(
            title="Set Password",
            text="Create a password to protect your sensitive data. "
            "This password is not shared with us nor with anyone else, so please store it securely."
            "\n\nEnter your new password:"******"Set Password",
                                   text="Please re-enter your password:"******"Passwords entered do not match, please try again."
        else:
            Security.login(password)
            # encrypt current timestamp as a dummy to prevent promping for password if bot exits without connecting an exchange
            dummy = f"{time.time()}"
            Security.update_secure_config("default", dummy)
    else:
        password = input_dialog(title="Welcome back to Hummingbot",
                                text="Enter your password:"******"Invalid password - please try again."
    if err_msg is not None:
        message_dialog(title='Error', text=err_msg, style=dialog_style).run()
        return login_prompt()
    return True
Ejemplo n.º 6
0
def save_to_yml(yml_path: str, cm: Dict[str, ConfigVar]):
    """
    Write current config saved a single config map into each a single yml file
    """
    try:
        with open(yml_path) as stream:
            data = yaml_parser.load(stream) or {}
            for key in cm:
                cvar = cm.get(key)
                if cvar.is_secure:
                    Security.update_secure_config(key, cvar.value)
                    if key in data:
                        data.pop(key)
                elif type(cvar.value) == Decimal:
                    data[key] = float(cvar.value)
                else:
                    data[key] = cvar.value
            with open(yml_path, "w+") as outfile:
                yaml_parser.dump(data, outfile)
    except Exception as e:
        logging.getLogger().error("Error writing configs: %s" % (str(e),), exc_info=True)
 async def _test_existing_password(self):
     # check the 2 encrypted files exist
     self.assertTrue(
         os.path.exists(f"{temp_folder}encrypted_test_key_1.json"))
     self.assertTrue(
         os.path.exists(f"{temp_folder}encrypted_test_key_2.json"))
     self.assertTrue(Security.any_encryped_files())
     self.assertFalse(Security.new_password_required())
     # login fails with incorrect password
     result = Security.login("b")
     self.assertFalse(result)
     # login passes with correct password
     result = Security.login("a")
     self.assertTrue(result)
     # right after logging in, the decryption shouldn't finished yet
     self.assertFalse(Security.is_decryption_done())
     await Security.wait_til_decryption_done()
     self.assertEqual(len(Security.all_decrypted_values()), 2)
     config_value = Security.decrypted_value("test_key_1")
     self.assertEqual("test_value_1", config_value)
     Security.update_secure_config("test_key_1", "new_value")
     self.assertEqual("new_value", Security.decrypted_value("test_key_1"))
Ejemplo n.º 8
0
 async def connect_exchange(
         self,  # type: HummingbotApplication
         exchange):
     self.app.clear_input()
     self.placeholder_mode = True
     self.app.hide_input = True
     exchange_configs = [
         c for c in global_config_map.values()
         if exchange in c.key and c.is_connect_key
     ]
     to_connect = True
     if Security.encrypted_file_exists(exchange_configs[0].key):
         await Security.wait_til_decryption_done()
         api_key_config = [
             c for c in exchange_configs if "api_key" in c.key
         ][0]
         api_key = Security.decrypted_value(api_key_config.key)
         answer = await self.app.prompt(
             prompt=
             f"Would you like to replace your existing {exchange} API key "
             f"...{api_key[-4:]} (Yes/No)? >>> ")
         if answer.lower() not in ("yes", "y"):
             to_connect = False
     if to_connect:
         for config in exchange_configs:
             await self.prompt_a_config(config)
             Security.update_secure_config(config.key, config.value)
         api_keys = (await Security.api_keys(exchange)).values()
         err_msg = await UserBalances.instance().add_exchange(
             exchange, *api_keys)
         if err_msg is None:
             self._notify(f"\nYou are now connected to {exchange}.")
         else:
             self._notify(f"\nError: {err_msg}")
     self.placeholder_mode = False
     self.app.hide_input = False
     self.app.change_prompt(prompt=">>> ")
Ejemplo n.º 9
0
def _maybe_migrate_encrypted_confs(config_keys: BaseConnectorConfigMap) -> List[str]:
    cm = ClientConfigAdapter(config_keys)
    found_one = False
    files_to_remove = []
    missing_fields = []
    for el in cm.traverse():
        if el.client_field_data is not None:
            if el.attr == "celo_address" and celo_address is not None:
                cm.setattr_no_validation(el.attr, celo_address)
                continue
            key_path = conf_dir_path / f"{encrypted_conf_prefix}{el.attr}{encrypted_conf_postfix}"
            if key_path.exists():
                with open(key_path, 'r') as f:
                    json_str = f.read()
                value = binascii.hexlify(json_str.encode()).decode()
                if not el.client_field_data.is_secure:
                    value = Security.secrets_manager.decrypt_secret_value(el.attr, value)
                cm.setattr_no_validation(el.attr, value)
                files_to_remove.append(key_path)
                found_one = True
            else:
                missing_fields.append(el.attr)
    errors = []
    if found_one:
        if len(missing_fields) != 0:
            errors = [f"{config_keys.connector} - missing fields: {missing_fields}"]
        if len(errors) == 0:
            errors = cm.validate_model()
        if errors:
            errors = [f"{config_keys.connector} - {e}" for e in errors]
            logging.getLogger().error(f"The migration of {config_keys.connector} failed with errors: {errors}")
        else:
            Security.update_secure_config(cm)
            logging.getLogger().info(f"Migrated secure keys for {config_keys.connector}")
        for f in files_to_remove:
            f.unlink()
    return errors