async def async_step_secure_knxkeys(self, user_input: dict | None = None ) -> FlowResult: """Configure secure knxkeys used to authenticate.""" errors = {} if user_input is not None: try: assert self._tunneling_config storage_key: str = (CONST_KNX_STORAGE_KEY + user_input[CONF_KNX_KNXKEY_FILENAME]) load_key_ring( self.hass.config.path( STORAGE_DIR, storage_key, ), user_input[CONF_KNX_KNXKEY_PASSWORD], ) entry_data: KNXConfigEntryData = { **self._tunneling_config, # type: ignore[misc] CONF_KNX_KNXKEY_FILENAME: storage_key, CONF_KNX_KNXKEY_PASSWORD: user_input[CONF_KNX_KNXKEY_PASSWORD], CONF_KNX_CONNECTION_TYPE: CONF_KNX_TUNNELING_TCP_SECURE, } return self.async_create_entry( title= f"Secure {CONF_KNX_TUNNELING.capitalize()} @ {self._tunneling_config[CONF_HOST]}", data=entry_data, ) except InvalidSignature: errors["base"] = "invalid_signature" except FileNotFoundError: errors["base"] = "file_not_found" fields = { vol.Required(CONF_KNX_KNXKEY_FILENAME): selector.selector({"text": {}}), vol.Required(CONF_KNX_KNXKEY_PASSWORD): selector.selector({"text": {}}), } return self.async_show_form(step_id="secure_knxkeys", data_schema=vol.Schema(fields), errors=errors)
def test_load_keyring(self): """Test load keyring from knxkeys file.""" keyring: Keyring = load_key_ring(self.keyring_test_file, "pwd") TestKeyRing.assert_interface(keyring, "user4", 2) TestKeyRing.assert_interface(keyring, "@zvI1G&_", 3) TestKeyRing.assert_interface(keyring, "ZvDY-:g#", 4) TestKeyRing.assert_interface(keyring, "user2", 5)
async def async_step_secure_knxkeys(self, user_input: dict | None = None ) -> FlowResult: """Configure secure knxkeys used to authenticate.""" errors = {} if user_input is not None: assert self._tunneling_config storage_key = CONST_KNX_STORAGE_KEY + user_input[ CONF_KNX_KNXKEY_FILENAME] try: load_key_ring( path=self.hass.config.path(STORAGE_DIR, storage_key), password=user_input[CONF_KNX_KNXKEY_PASSWORD], ) except FileNotFoundError: errors[CONF_KNX_KNXKEY_FILENAME] = "file_not_found" except InvalidSignature: errors[CONF_KNX_KNXKEY_PASSWORD] = "invalid_signature" if not errors: entry_data = self._tunneling_config | KNXConfigEntryData( connection_type=CONF_KNX_TUNNELING_TCP_SECURE, knxkeys_filename=storage_key, knxkeys_password=user_input[CONF_KNX_KNXKEY_PASSWORD], ) return self.async_create_entry( title= f"Secure Tunneling @ {self._tunneling_config[CONF_HOST]}", data=entry_data, ) fields = { vol.Required(CONF_KNX_KNXKEY_FILENAME): selector.TextSelector(), vol.Required(CONF_KNX_KNXKEY_PASSWORD): selector.TextSelector(), } return self.async_show_form(step_id="secure_knxkeys", data_schema=vol.Schema(fields), errors=errors)
def test_load_keyring_real(self): """Test load keyring from knxkeys file.""" keyring: Keyring = load_key_ring(self.testcase_file, "password") TestKeyRing.assert_interface(keyring, "user1", 3) TestKeyRing.assert_interface(keyring, "user2", 4) TestKeyRing.assert_interface(keyring, "user3", 5) TestKeyRing.assert_interface(keyring, "user4", 6) assert keyring.devices[ 0].decrypted_management_password == "commissioning" interface: XMLInterface = keyring.interfaces[0] device: XMLDevice = keyring.get_device_by_interface(interface) assert device is not None assert device.decrypted_authentication == "authenticationcode"
async def _start(self) -> None: """Start interface. Connecting KNX/IP device with the selected method.""" if self.connection_config.connection_type == ConnectionType.ROUTING: await self._start_routing(local_ip=self.connection_config.local_ip) elif (self.connection_config.connection_type == ConnectionType.TUNNELING and self.connection_config.gateway_ip is not None): await self._start_tunnelling_udp( gateway_ip=self.connection_config.gateway_ip, gateway_port=self.connection_config.gateway_port, ) elif (self.connection_config.connection_type == ConnectionType.TUNNELING_TCP and self.connection_config.gateway_ip is not None): await self._start_tunnelling_tcp( gateway_ip=self.connection_config.gateway_ip, gateway_port=self.connection_config.gateway_port, ) elif (self.connection_config.connection_type == ConnectionType.TUNNELING_TCP_SECURE and self.connection_config.gateway_ip is not None and self.connection_config.secure_config is not None): secure_config = self.connection_config.secure_config user_id: int user_password: str device_authentication_password: str | None if (secure_config.knxkeys_file_path is not None and secure_config.knxkeys_password is not None): keyring: Keyring = load_key_ring( secure_config.knxkeys_file_path, secure_config.knxkeys_password) if secure_config.user_id is not None: user_id = secure_config.user_id interface = keyring.get_interface_by_user_id(user_id) if interface is None: raise InterfaceWithUserIdNotFound() user_password = interface.decrypted_password device_authentication_password = interface.decrypted_authentication else: interface = keyring.interfaces[0] user_id = interface.user_id user_password = interface.decrypted_password device_authentication_password = interface.decrypted_authentication else: user_id = secure_config.user_id or 2 if secure_config.user_password is None: raise InvalidSecureConfiguration() user_password = secure_config.user_password device_authentication_password = ( secure_config.device_authentication_password) await self._start_secure_tunnelling_tcp( gateway_ip=self.connection_config.gateway_ip, gateway_port=self.connection_config.gateway_port, user_id=user_id, user_password=user_password, device_authentication_password=device_authentication_password, ) else: await self._start_automatic()
def test_raises_error(self): """Test raises error if password is wrong.""" with pytest.raises(InvalidSecureConfiguration): load_key_ring(self.testcase_file, "wrong_password", validate_signature=False)
def test_invalid_signature(self): """Test invalid signature throws error.""" with pytest.raises(InvalidSignature): load_key_ring(self.testcase_file, "wrong_password")