diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index f76e7e16b11..4ab0bfee351 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -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 https://home-assistant.io/developers/api/ """ -import json -import threading -import logging -import time -import gzip -import os from datetime import timedelta -from http.server import SimpleHTTPRequestHandler, HTTPServer +import gzip from http import cookies +from http.server import SimpleHTTPRequestHandler, HTTPServer +import json +import logging +import os from socketserver import ThreadingMixIn +import ssl +import threading +import time from urllib.parse import urlparse, parse_qs import homeassistant.core as ha @@ -36,6 +37,8 @@ CONF_API_PASSWORD = "api_password" CONF_SERVER_HOST = "server_host" CONF_SERVER_PORT = "server_port" CONF_DEVELOPMENT = "development" +CONF_SSL_CERTIFICATE = 'ssl_certificate' +CONF_SSL_KEY = 'ssl_key' 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_port = conf.get(CONF_SERVER_PORT, SERVER_PORT) development = str(conf.get(CONF_DEVELOPMENT, "")) == "1" + ssl_certificate = conf.get(CONF_SSL_CERTIFICATE) + ssl_key = conf.get(CONF_SSL_KEY) try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, - development) + development, ssl_certificate, ssl_key) except OSError: # If address already in use _LOGGER.exception("Error setting up HTTP server") @@ -73,7 +78,8 @@ def setup(hass, config): threading.Thread(target=server.start, daemon=True).start()) 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 @@ -88,7 +94,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): # pylint: disable=too-many-arguments 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) self.server_address = server_address @@ -97,6 +103,7 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): self.development = development self.paths = [] self.sessions = SessionStore() + self.use_ssl = ssl_certificate is not None # We will lazy init this one if needed self.event_forwarder = None @@ -104,6 +111,12 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): if development: _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): """ Starts the HTTP server. """ def stop_http(event): @@ -112,8 +125,11 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): self.hass.bus.listen_once(ha.EVENT_HOMEASSISTANT_STOP, stop_http) + protocol = 'https' if self.use_ssl else 'http' + _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 # To prevent stuff from breaking, load the two extracted components diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 72f95ca389a..3b47b60365c 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -51,11 +51,14 @@ class API(object): """ Object to pass around Home Assistant API location and credentials. """ # 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.port = port or SERVER_PORT self.api_password = api_password - self.base_url = "http://{}:{}".format(host, self.port) + if use_ssl: + self.base_url = "https://{}:{}".format(host, self.port) + else: + self.base_url = "http://{}:{}".format(host, self.port) self.status = None self._headers = {}