From fe794d7fd8beecbb222a86966da6f3a04731c5da Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 15 May 2016 16:59:27 -0700 Subject: [PATCH] Access camera images using access token --- homeassistant/components/camera/__init__.py | 44 +++++++++++++++------ homeassistant/components/http.py | 9 ++--- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 1a6fa2cb956..05be02a9491 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -52,6 +52,11 @@ class Camera(Entity): """Initialize a camera.""" self.is_streaming = False + @property + def access_token(self): + """Access token for this camera.""" + return str(id(self)) + @property def should_poll(self): """No need to poll cameras.""" @@ -124,7 +129,9 @@ class Camera(Entity): @property def state_attributes(self): """Camera state attributes.""" - attr = {} + attr = { + 'access_token': self.access_token, + } if self.model: attr['model_name'] = self.model @@ -138,11 +145,32 @@ class Camera(Entity): class CameraView(HomeAssistantView): """Base CameraView.""" + requires_auth = False + def __init__(self, hass, entities): """Initialize a basic camera view.""" super().__init__(hass) self.entities = entities + def get(self, request, entity_id): + """Start a get request.""" + camera = self.entities.get(entity_id) + + if camera is None: + return self.Response(status=404) + + authenticated = (request.authenticated or + request.args.get('token') == camera.access_token) + + if not authenticated: + return self.Response(status=401) + + return self.handle(camera) + + def handle(self, camera): + """Hanlde the camera request.""" + raise NotImplementedError() + class CameraImageView(CameraView): """Camera view to serve an image.""" @@ -150,13 +178,8 @@ class CameraImageView(CameraView): url = "/api/camera_proxy/" name = "api:camera:image" - def get(self, request, entity_id): + def handle(self, camera): """Serve camera image.""" - camera = self.entities.get(entity_id) - - if camera is None: - return self.Response(status=404) - response = camera.camera_image() if response is None: @@ -171,11 +194,6 @@ class CameraMjpegStream(CameraView): url = "/api/camera_proxy_stream/" name = "api:camera:stream" - def get(self, request, entity_id): + def handle(self, camera): """Serve camera image.""" - camera = self.entities.get(entity_id) - - if camera is None: - return self.Response(status=404) - return camera.mjpeg_stream(self.Response()) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 6d9a6522617..d4965eb05c4 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -339,10 +339,7 @@ class HomeAssistantView(object): # Auth code verbose on purpose authenticated = False - if not self.requires_auth: - authenticated = True - - elif self.hass.wsgi.api_password is None: + if self.hass.wsgi.api_password is None: authenticated = True elif hmac.compare_digest(request.headers.get(HTTP_HEADER_HA_AUTH, ''), @@ -366,9 +363,11 @@ class HomeAssistantView(object): except BadRequest: pass - if not authenticated: + if self.requires_auth and not authenticated: raise Unauthorized() + request.authenticated = authenticated + result = handler(request, **values) if isinstance(result, self.Response):