Merge pull request #706 from balloob/dev

0.9.1
This commit is contained in:
Paulus Schoutsen 2015-12-06 21:18:57 -08:00
commit 2c157e6885
10 changed files with 61 additions and 34 deletions

View File

@ -52,7 +52,7 @@ omit =
homeassistant/components/discovery.py homeassistant/components/discovery.py
homeassistant/components/downloader.py homeassistant/components/downloader.py
homeassistant/components/ifttt.py homeassistant/components/ifttt.py
homeassistant/components/influx.py homeassistant/components/influxdb.py
homeassistant/components/keyboard.py homeassistant/components/keyboard.py
homeassistant/components/light/hue.py homeassistant/components/light/hue.py
homeassistant/components/light/mqtt.py homeassistant/components/light/mqtt.py

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """ """ DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "8470cd10f28b20eae9022fa4c8f40c1b" VERSION = "d07b7ed1734ae3f2472f9ae88e0c3dea"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit feb776ec89d6872dad2203b352cc6d652c46356d Subproject commit 044a6d9810b6aa662b82af0f67deb662725ad4cb

View File

@ -6,16 +6,17 @@ This module provides an API and a HTTP interface for debug purposes.
For more details about the RESTful API, please refer to the documentation at For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api/ https://home-assistant.io/developers/api/
""" """
import json
import threading
import logging
import time
import gzip
import os
from datetime import timedelta from datetime import timedelta
from http.server import SimpleHTTPRequestHandler, HTTPServer import gzip
from http import cookies from http import cookies
from http.server import SimpleHTTPRequestHandler, HTTPServer
import json
import logging
import os
from socketserver import ThreadingMixIn from socketserver import ThreadingMixIn
import ssl
import threading
import time
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
import homeassistant.core as ha import homeassistant.core as ha
@ -36,6 +37,8 @@ CONF_API_PASSWORD = "api_password"
CONF_SERVER_HOST = "server_host" CONF_SERVER_HOST = "server_host"
CONF_SERVER_PORT = "server_port" CONF_SERVER_PORT = "server_port"
CONF_DEVELOPMENT = "development" CONF_DEVELOPMENT = "development"
CONF_SSL_CERTIFICATE = 'ssl_certificate'
CONF_SSL_KEY = 'ssl_key'
DATA_API_PASSWORD = 'api_password' DATA_API_PASSWORD = 'api_password'
@ -57,11 +60,13 @@ def setup(hass, config):
server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0')
server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT)
development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" development = str(conf.get(CONF_DEVELOPMENT, "")) == "1"
ssl_certificate = conf.get(CONF_SSL_CERTIFICATE)
ssl_key = conf.get(CONF_SSL_KEY)
try: try:
server = HomeAssistantHTTPServer( server = HomeAssistantHTTPServer(
(server_host, server_port), RequestHandler, hass, api_password, (server_host, server_port), RequestHandler, hass, api_password,
development) development, ssl_certificate, ssl_key)
except OSError: except OSError:
# If address already in use # If address already in use
_LOGGER.exception("Error setting up HTTP server") _LOGGER.exception("Error setting up HTTP server")
@ -73,7 +78,8 @@ def setup(hass, config):
threading.Thread(target=server.start, daemon=True).start()) threading.Thread(target=server.start, daemon=True).start())
hass.http = server hass.http = server
hass.config.api = rem.API(util.get_local_ip(), api_password, server_port) hass.config.api = rem.API(util.get_local_ip(), api_password, server_port,
ssl_certificate is not None)
return True return True
@ -88,7 +94,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
def __init__(self, server_address, request_handler_class, def __init__(self, server_address, request_handler_class,
hass, api_password, development): hass, api_password, development, ssl_certificate, ssl_key):
super().__init__(server_address, request_handler_class) super().__init__(server_address, request_handler_class)
self.server_address = server_address self.server_address = server_address
@ -97,6 +103,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
self.development = development self.development = development
self.paths = [] self.paths = []
self.sessions = SessionStore() self.sessions = SessionStore()
self.use_ssl = ssl_certificate is not None
# We will lazy init this one if needed # We will lazy init this one if needed
self.event_forwarder = None self.event_forwarder = None
@ -104,6 +111,12 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
if development: if development:
_LOGGER.info("running http in development mode") _LOGGER.info("running http in development mode")
if ssl_certificate is not None:
wrap_kwargs = {'certfile': ssl_certificate}
if ssl_key is not None:
wrap_kwargs['keyfile'] = ssl_key
self.socket = ssl.wrap_socket(self.socket, **wrap_kwargs)
def start(self): def start(self):
""" Starts the HTTP server. """ """ Starts the HTTP server. """
def stop_http(event): def stop_http(event):
@ -112,8 +125,11 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http) self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http)
protocol = 'https' if self.use_ssl else 'http'
_LOGGER.info( _LOGGER.info(
"Starting web interface at http://%s:%d", *self.server_address) "Starting web interface at %s://%s:%d",
protocol, self.server_address[0], self.server_address[1])
# 31-1-2015: Refactored frontend/api components out of this component # 31-1-2015: Refactored frontend/api components out of this component
# To prevent stuff from breaking, load the two extracted components # To prevent stuff from breaking, load the two extracted components
@ -186,17 +202,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
"Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY) "Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY)
return return
if self.server.api_password is None: self.authenticated = (self.server.api_password is None
self.authenticated = True or self.headers.get(HTTP_HEADER_HA_AUTH) ==
elif HTTP_HEADER_HA_AUTH in self.headers: self.server.api_password
api_password = self.headers.get(HTTP_HEADER_HA_AUTH) or data.get(DATA_API_PASSWORD) ==
self.server.api_password
if not api_password and DATA_API_PASSWORD in data: or self.verify_session())
api_password = data[DATA_API_PASSWORD]
self.authenticated = api_password == self.server.api_password
else:
self.authenticated = self.verify_session()
if '_METHOD' in data: if '_METHOD' in data:
method = data.pop('_METHOD') method = data.pop('_METHOD')

View File

@ -1,7 +1,7 @@
# coding: utf-8 # coding: utf-8
""" Constants used by Home Assistant components. """ """ Constants used by Home Assistant components. """
__version__ = "0.9.0" __version__ = "0.9.1"
# Can be used to specify a catch all when registering state or event listeners. # Can be used to specify a catch all when registering state or event listeners.
MATCH_ALL = '*' MATCH_ALL = '*'

View File

@ -51,10 +51,13 @@ class API(object):
""" Object to pass around Home Assistant API location and credentials. """ """ Object to pass around Home Assistant API location and credentials. """
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
def __init__(self, host, api_password=None, port=None): def __init__(self, host, api_password=None, port=None, use_ssl=False):
self.host = host self.host = host
self.port = port or SERVER_PORT self.port = port or SERVER_PORT
self.api_password = api_password self.api_password = api_password
if use_ssl:
self.base_url = "https://{}:{}".format(host, self.port)
else:
self.base_url = "http://{}:{}".format(host, self.port) self.base_url = "http://{}:{}".format(host, self.port)
self.status = None self.status = None
self._headers = {} self._headers = {}

View File

@ -26,7 +26,7 @@ https://github.com/nkgilley/python-ecobee-api/archive/92a2f330cbaf601d0618456fdd
# homeassistant.components.ifttt # homeassistant.components.ifttt
pyfttt==0.3 pyfttt==0.3
# homeassistant.components.influx # homeassistant.components.influxdb
influxdb==2.10.0 influxdb==2.10.0
# homeassistant.components.isy994 # homeassistant.components.isy994

View File

@ -66,18 +66,31 @@ class TestAPI(unittest.TestCase):
# TODO move back to http component and test with use_auth. # TODO move back to http component and test with use_auth.
def test_access_denied_without_password(self): def test_access_denied_without_password(self):
req = requests.get( req = requests.get(_url(const.URL_API))
_url(const.URL_API_STATES_ENTITY.format("test")))
self.assertEqual(401, req.status_code) self.assertEqual(401, req.status_code)
def test_access_denied_with_wrong_password(self): def test_access_denied_with_wrong_password(self):
req = requests.get( req = requests.get(
_url(const.URL_API_STATES_ENTITY.format("test")), _url(const.URL_API),
headers={const.HTTP_HEADER_HA_AUTH: 'wrongpassword'}) headers={const.HTTP_HEADER_HA_AUTH: 'wrongpassword'})
self.assertEqual(401, req.status_code) self.assertEqual(401, req.status_code)
def test_access_with_password_in_url(self):
req = requests.get(
"{}?api_password={}".format(_url(const.URL_API), API_PASSWORD))
self.assertEqual(200, req.status_code)
def test_access_via_session(self):
session = requests.Session()
req = session.get(_url(const.URL_API), headers=HA_HEADERS)
self.assertEqual(200, req.status_code)
req = session.get(_url(const.URL_API))
self.assertEqual(200, req.status_code)
def test_api_list_state_entities(self): def test_api_list_state_entities(self):
""" Test if the debug interface allows us to list state entities. """ """ Test if the debug interface allows us to list state entities. """
req = requests.get(_url(const.URL_API_STATES), req = requests.get(_url(const.URL_API_STATES),