diff --git a/homeassistant/components/device_tracker/gpslogger.py b/homeassistant/components/device_tracker/gpslogger.py index b88245ac9a5..1952e6d676d 100644 --- a/homeassistant/components/device_tracker/gpslogger.py +++ b/homeassistant/components/device_tracker/gpslogger.py @@ -5,23 +5,37 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/device_tracker.gpslogger/ """ import asyncio -from functools import partial import logging +from hmac import compare_digest -from homeassistant.const import HTTP_UNPROCESSABLE_ENTITY -from homeassistant.components.http import HomeAssistantView +from aiohttp.web import Request, HTTPUnauthorized # NOQA +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_PASSWORD, HTTP_UNPROCESSABLE_ENTITY +) +from homeassistant.components.http import ( + CONF_API_PASSWORD, HomeAssistantView +) # pylint: disable=unused-import from homeassistant.components.device_tracker import ( # NOQA - DOMAIN, PLATFORM_SCHEMA) + DOMAIN, PLATFORM_SCHEMA +) _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['http'] +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_PASSWORD): cv.string, +}) -def setup_scanner(hass, config, see, discovery_info=None): + +@asyncio.coroutine +def async_setup_scanner(hass, config, async_see, discovery_info=None): """Set up an endpoint for the GPSLogger application.""" - hass.http.register_view(GPSLoggerView(see)) + hass.http.register_view(GPSLoggerView(async_see, config)) return True @@ -32,26 +46,36 @@ class GPSLoggerView(HomeAssistantView): url = '/api/gpslogger' name = 'api:gpslogger' - def __init__(self, see): + def __init__(self, async_see, config): """Initialize GPSLogger url endpoints.""" - self.see = see + self.async_see = async_see + self._password = config.get(CONF_PASSWORD) + # this component does not require external authentication if + # password is set + self.requires_auth = self._password is None @asyncio.coroutine - def get(self, request): + def get(self, request: Request): """Handle for GPSLogger message received as GET.""" - res = yield from self._handle(request.app['hass'], request.query) - return res + hass = request.app['hass'] + data = request.query + + if self._password is not None: + authenticated = CONF_API_PASSWORD in data and compare_digest( + self._password, + data[CONF_API_PASSWORD] + ) + if not authenticated: + raise HTTPUnauthorized() - @asyncio.coroutine - def _handle(self, hass, data): - """Handle GPSLogger requests.""" if 'latitude' not in data or 'longitude' not in data: return ('Latitude and longitude not specified.', HTTP_UNPROCESSABLE_ENTITY) if 'device' not in data: _LOGGER.error("Device id not specified") - return ('Device id not specified.', HTTP_UNPROCESSABLE_ENTITY) + return ('Device id not specified.', + HTTP_UNPROCESSABLE_ENTITY) device = data['device'].replace('-', '') gps_location = (data['latitude'], data['longitude']) @@ -75,10 +99,11 @@ class GPSLoggerView(HomeAssistantView): if 'activity' in data: attrs['activity'] = data['activity'] - yield from hass.async_add_job( - partial(self.see, dev_id=device, - gps=gps_location, battery=battery, - gps_accuracy=accuracy, - attributes=attrs)) + hass.async_add_job(self.async_see( + dev_id=device, + gps=gps_location, battery=battery, + gps_accuracy=accuracy, + attributes=attrs + )) return 'Setting location for {}'.format(device)