From 68d72931c43c974d0f629d0872ca6a0bd7e11b99 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 8 Oct 2018 20:50:24 +0200 Subject: [PATCH] block external IP (#17248) * block external IP * Update __init__.py --- .../components/emulated_hue/__init__.py | 15 ++++++++++-- .../components/emulated_hue/hue_api.py | 23 +++++++++++++++++++ tests/components/emulated_hue/test_hue_api.py | 10 ++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/emulated_hue/__init__.py b/homeassistant/components/emulated_hue/__init__.py index 8a67b933b9f..5f1d61dd602 100644 --- a/homeassistant/components/emulated_hue/__init__.py +++ b/homeassistant/components/emulated_hue/__init__.py @@ -18,6 +18,8 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.deprecation import get_deprecated import homeassistant.helpers.config_validation as cv from homeassistant.util.json import load_json, save_json +from homeassistant.components.http import real_ip + from .hue_api import ( HueUsernameView, HueAllLightsStateView, HueOneLightStateView, HueOneLightChangeView, HueGroupView) @@ -81,12 +83,20 @@ ATTR_EMULATED_HUE_NAME = 'emulated_hue_name' ATTR_EMULATED_HUE_HIDDEN = 'emulated_hue_hidden' -def setup(hass, yaml_config): +async def async_setup(hass, yaml_config): """Activate the emulated_hue component.""" config = Config(hass, yaml_config.get(DOMAIN, {})) app = web.Application() app['hass'] = hass + + real_ip.setup_real_ip(app, False, []) + # We misunderstood the startup signal. You're not allowed to change + # anything during startup. Temp workaround. + # pylint: disable=protected-access + app._on_startup.freeze() + await app.startup() + handler = None server = None @@ -131,7 +141,8 @@ def setup(hass, yaml_config): hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STOP, stop_emulated_hue_bridge) - hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_emulated_hue_bridge) + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, + start_emulated_hue_bridge) return True diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index c6fa622513b..3699a45ef30 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -20,6 +20,9 @@ from homeassistant.components.fan import ( SPEED_MEDIUM, SPEED_HIGH ) from homeassistant.components.http import HomeAssistantView +from homeassistant.components.http.const import KEY_REAL_IP +from homeassistant.util.network import is_local + _LOGGER = logging.getLogger(__name__) @@ -46,6 +49,10 @@ class HueUsernameView(HomeAssistantView): return self.json_message('devicetype not specified', HTTP_BAD_REQUEST) + if not is_local(request[KEY_REAL_IP]): + return self.json_message('only local IPs allowed', + HTTP_BAD_REQUEST) + return self.json([{'success': {'username': '12345678901234567890'}}]) @@ -63,6 +70,10 @@ class HueGroupView(HomeAssistantView): @core.callback def put(self, request, username): """Process a request to make the Logitech Pop working.""" + if not is_local(request[KEY_REAL_IP]): + return self.json_message('only local IPs allowed', + HTTP_BAD_REQUEST) + return self.json([{ 'error': { 'address': '/groups/0/action/scene', @@ -86,6 +97,10 @@ class HueAllLightsStateView(HomeAssistantView): @core.callback def get(self, request, username): """Process a request to get the list of available lights.""" + if not is_local(request[KEY_REAL_IP]): + return self.json_message('only local IPs allowed', + HTTP_BAD_REQUEST) + hass = request.app['hass'] json_response = {} @@ -114,6 +129,10 @@ class HueOneLightStateView(HomeAssistantView): @core.callback def get(self, request, username, entity_id): """Process a request to get the state of an individual light.""" + if not is_local(request[KEY_REAL_IP]): + return self.json_message('only local IPs allowed', + HTTP_BAD_REQUEST) + hass = request.app['hass'] entity_id = self.config.number_to_entity_id(entity_id) entity = hass.states.get(entity_id) @@ -146,6 +165,10 @@ class HueOneLightChangeView(HomeAssistantView): async def put(self, request, username, entity_number): """Process a request to set the state of an individual light.""" + if not is_local(request[KEY_REAL_IP]): + return self.json_message('only local IPs allowed', + HTTP_BAD_REQUEST) + config = self.config hass = request.app['hass'] entity_id = config.number_to_entity_id(entity_number) diff --git a/tests/components/emulated_hue/test_hue_api.py b/tests/components/emulated_hue/test_hue_api.py index 3920a45ddf6..8582f5b38cf 100644 --- a/tests/components/emulated_hue/test_hue_api.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -1,6 +1,7 @@ """The tests for the emulated Hue component.""" import asyncio import json +from ipaddress import ip_address from unittest.mock import patch from aiohttp.hdrs import CONTENT_TYPE @@ -484,3 +485,12 @@ def perform_put_light_state(hass_hue, client, entity_id, is_on, yield from hass_hue.async_block_till_done() return result + + +async def test_external_ip_blocked(hue_client): + """Test external IP blocked.""" + with patch('homeassistant.components.http.real_ip.ip_address', + return_value=ip_address('45.45.45.45')): + result = await hue_client.get('/api/username/lights') + + assert result.status == 400