diff --git a/API.md b/API.md index 5123745bf..e6720bd71 100644 --- a/API.md +++ b/API.md @@ -4,7 +4,7 @@ Interface for Home Assistant to control things from supervisor. -On error: +On error / Code 400: ```json { @@ -13,7 +13,7 @@ On error: } ``` -On success: +On success / Code 200: ```json { @@ -22,6 +22,8 @@ On success: } ``` +For access to API you need set the `X-HASSIO-KEY` they will be available for Add-ons/HomeAssistant with envoriment `HASSIO_TOKEN`. + ### Hass.io - GET `/supervisor/ping` @@ -99,44 +101,7 @@ Output is the raw docker log. } ``` -### Security - -- GET `/security/info` - -```json -{ - "initialize": "bool", - "totp": "bool" -} -``` - -- POST `/security/options` - -```json -{ - "password": "xy" -} -``` - -- POST `/security/totp` - -```json -{ - "password": "xy" -} -``` - -Return QR-Code - -- POST `/security/session` -```json -{ - "password": "xy", - "totp": "null|123456" -} -``` - -### Backup/Snapshot +### Snapshot - GET `/snapshots` diff --git a/README.md b/README.md index 71ff79643..e4101e998 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # Hass.io -### First private cloud solution for home automation. +## First private cloud solution for home automation -Hass.io is a Docker based system for managing your Home Assistant installation and related applications. The system is controlled via Home Assistant which communicates with the supervisor. The supervisor provides an API to manage the installation. This includes changing network settings or installing and updating software. +Hass.io is a Docker-based system for managing your Home Assistant installation +and related applications. The system is controlled via Home Assistant which +communicates with the Supervisor. The Supervisor provides an API to manage the +installation. This includes changing network settings or installing +and updating software. ![](misc/hassio.png?raw=true) @@ -11,4 +15,4 @@ Hass.io is a Docker based system for managing your Home Assistant installation a ## Installation -Installation instructions can be found at [https://home-assistant.io/hassio](https://home-assistant.io/hassio). +Installation instructions can be found at . diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 032a2ec56..7944de1b6 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -160,7 +160,7 @@ class Addon(CoreSysAttributes): return self._mesh[ATTR_TIMEOUT] @property - def api_token(self): + def uuid(self): """Return a API token for this add-on.""" if self.is_installed: return self._data.user[self._id][ATTR_UUID] diff --git a/hassio/api/__init__.py b/hassio/api/__init__.py index 5601d469d..80df80edf 100644 --- a/hassio/api/__init__.py +++ b/hassio/api/__init__.py @@ -10,7 +10,6 @@ from .host import APIHost from .network import APINetwork from .proxy import APIProxy from .supervisor import APISupervisor -from .security import APISecurity from .snapshots import APISnapshots from ..coresys import CoreSysAttributes @@ -38,7 +37,6 @@ class RestAPI(CoreSysAttributes): self._register_panel() self._register_addons() self._register_snapshots() - self._register_security() self._register_network() def _register_host(self): @@ -102,12 +100,14 @@ class RestAPI(CoreSysAttributes): '/homeassistant/api/websocket', api_proxy.websocket) self.webapp.router.add_get( '/homeassistant/websocket', api_proxy.websocket) + self.webapp.router.add_get( + '/homeassistant/api/stream', api_proxy.stream) self.webapp.router.add_post( '/homeassistant/api/{path:.+}', api_proxy.api) self.webapp.router.add_get( '/homeassistant/api/{path:.+}', api_proxy.api) self.webapp.router.add_get( - '/homeassistant/api', api_proxy.api) + '/homeassistant/api/', api_proxy.api) def _register_addons(self): """Register homeassistant function.""" @@ -138,16 +138,6 @@ class RestAPI(CoreSysAttributes): self.webapp.router.add_post('/addons/{addon}/stdin', api_addons.stdin) self.webapp.router.add_get('/addons/{addon}/stats', api_addons.stats) - def _register_security(self): - """Register security function.""" - api_security = APISecurity() - api_security.coresys = self.coresys - - self.webapp.router.add_get('/security/info', api_security.info) - self.webapp.router.add_post('/security/options', api_security.options) - self.webapp.router.add_post('/security/totp', api_security.totp) - self.webapp.router.add_post('/security/session', api_security.session) - def _register_snapshots(self): """Register snapshots function.""" api_snapshots = APISnapshots() diff --git a/hassio/api/addons.py b/hassio/api/addons.py index bf670dd74..8f593f79f 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -267,7 +267,7 @@ class APIAddons(CoreSysAttributes): """Write to stdin of addon.""" addon = self._extract_addon(request) if not addon.with_stdin: - raise RuntimeError("STDIN not supported by addons") + raise RuntimeError("STDIN not supported by addon") data = await request.read() return await asyncio.shield(addon.write_stdin(data), loop=self._loop) diff --git a/hassio/api/proxy.py b/hassio/api/proxy.py index 4ea7cb58a..9b25ec618 100644 --- a/hassio/api/proxy.py +++ b/hassio/api/proxy.py @@ -25,6 +25,7 @@ class APIProxy(CoreSysAttributes): data = None headers = {} method = getattr(self._websession_ssl, request.method.lower()) + params = request.query or None # read data with async_timeout.timeout(30, loop=self._loop): @@ -42,7 +43,8 @@ class APIProxy(CoreSysAttributes): headers = None client = await method( - url, data=data, headers=headers, timeout=timeout + url, data=data, headers=headers, timeout=timeout, + params=params ) return client @@ -55,48 +57,46 @@ class APIProxy(CoreSysAttributes): raise HTTPBadGateway() + async def stream(self, request): + """Proxy HomeAssistant EventStream Requests.""" + _LOGGER.info("Home-Assistant EventStream start") + client = await self._api_client(request, 'stream', timeout=None) + + response = web.StreamResponse() + response.content_type = request.headers.get(CONTENT_TYPE) + try: + await response.prepare(request) + while True: + data = await client.content.read(10) + if not data: + await response.write_eof() + break + response.write(data) + + except aiohttp.ClientError: + await response.write_eof() + + except asyncio.CancelledError: + pass + + finally: + client.close() + _LOGGER.info("Home-Assistant EventStream close") + async def api(self, request): """Proxy HomeAssistant API Requests.""" path = request.match_info.get('path', '') - # API stream - if path.startswith("stream"): - _LOGGER.info("Home-Assistant Event-Stream start") - client = await self._api_client(request, path, timeout=None) - - response = web.StreamResponse() - response.content_type = request.headers.get(CONTENT_TYPE) - try: - await response.prepare(request) - while True: - data = await client.content.read(10) - if not data: - await response.write_eof() - break - response.write(data) - - except aiohttp.ClientError: - await response.write_eof() - - except asyncio.CancelledError: - pass - - finally: - client.close() - - _LOGGER.info("Home-Assistant Event-Stream close") - # Normal request - else: - _LOGGER.info("Home-Assistant '/api/%s' request", path) - client = await self._api_client(request, path) + _LOGGER.info("Home-Assistant /api/%s request", path) + client = await self._api_client(request, path) - data = await client.read() - return web.Response( - body=data, - status=client.status, - content_type=client.content_type - ) + data = await client.read() + return web.Response( + body=data, + status=client.status, + content_type=client.content_type + ) async def _websocket_client(self): """Initialize a websocket api connection.""" diff --git a/hassio/api/security.py b/hassio/api/security.py deleted file mode 100644 index cbb56b0b0..000000000 --- a/hassio/api/security.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Init file for HassIO security rest api.""" -from datetime import datetime, timedelta -import io -import logging -import hashlib -import os - -from aiohttp import web -import voluptuous as vol -import pyotp -import pyqrcode - -from .utils import api_process, api_validate, hash_password -from ..const import ATTR_INITIALIZE, ATTR_PASSWORD, ATTR_TOTP, ATTR_SESSION -from ..coresys import CoreSysAttributes - -_LOGGER = logging.getLogger(__name__) - -SCHEMA_PASSWORD = vol.Schema({ - vol.Required(ATTR_PASSWORD): vol.Coerce(str), -}) - -SCHEMA_SESSION = SCHEMA_PASSWORD.extend({ - vol.Optional(ATTR_TOTP, default=None): vol.Coerce(str), -}) - - -class APISecurity(CoreSysAttributes): - """Handle rest api for security functions.""" - - def _check_password(self, body): - """Check if password is valid and security is initialize.""" - if not self._config.security_initialize: - raise RuntimeError("First set a password") - - password = hash_password(body[ATTR_PASSWORD]) - if password != self._config.security_password: - raise RuntimeError("Wrong password") - - @api_process - async def info(self, request): - """Return host information.""" - return { - ATTR_INITIALIZE: self._config.security_initialize, - ATTR_TOTP: self._config.security_totp is not None, - } - - @api_process - async def options(self, request): - """Set options / password.""" - body = await api_validate(SCHEMA_PASSWORD, request) - - if self._config.security_initialize: - raise RuntimeError("Password is already set!") - - self._config.security_password = hash_password(body[ATTR_PASSWORD]) - self._config.security_initialize = True - return True - - @api_process - async def totp(self, request): - """Set and initialze TOTP.""" - body = await api_validate(SCHEMA_PASSWORD, request) - self._check_password(body) - - # generate TOTP - totp_init_key = pyotp.random_base32() - totp = pyotp.TOTP(totp_init_key) - - # init qrcode - buff = io.BytesIO() - - qrcode = pyqrcode.create(totp.provisioning_uri("Hass.IO")) - qrcode.svg(buff) - - # finish - self._config.security_totp = totp_init_key - return web.Response(body=buff.getvalue(), content_type='image/svg+xml') - - @api_process - async def session(self, request): - """Set and initialze session.""" - body = await api_validate(SCHEMA_SESSION, request) - self._check_password(body) - - # check TOTP - if self._config.security_totp: - totp = pyotp.TOTP(self._config.security_totp) - if body[ATTR_TOTP] != totp.now(): - raise RuntimeError("Invalid TOTP token!") - - # create session - valid_until = datetime.now() + timedelta(days=1) - session = hashlib.sha256(os.urandom(54)).hexdigest() - - # store session - self._config.add_security_session(session, valid_until) - return {ATTR_SESSION: session} diff --git a/hassio/config.py b/hassio/config.py index 3df086e07..6e50f0bc2 100644 --- a/hassio/config.py +++ b/hassio/config.py @@ -5,8 +5,7 @@ import os from pathlib import Path, PurePath from .const import ( - FILE_HASSIO_CONFIG, HASSIO_DATA, ATTR_SECURITY, ATTR_SESSIONS, - ATTR_PASSWORD, ATTR_TOTP, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST, + FILE_HASSIO_CONFIG, HASSIO_DATA, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST, ATTR_AUDIO_INPUT, ATTR_AUDIO_OUTPUT, ATTR_LAST_BOOT, ATTR_WAIT_BOOT) from .utils.dt import parse_datetime from .utils.json import JsonConfig @@ -181,59 +180,6 @@ class CoreConfig(JsonConfig): self._data[ATTR_ADDONS_CUSTOM_LIST].remove(repo) self.save() - @property - def security_initialize(self): - """Return is security was initialize.""" - return self._data[ATTR_SECURITY] - - @security_initialize.setter - def security_initialize(self, value): - """Set is security initialize.""" - self._data[ATTR_SECURITY] = value - self.save() - - @property - def security_totp(self): - """Return the TOTP key.""" - return self._data.get(ATTR_TOTP) - - @security_totp.setter - def security_totp(self, value): - """Set the TOTP key.""" - self._data[ATTR_TOTP] = value - self.save() - - @property - def security_password(self): - """Return the password key.""" - return self._data.get(ATTR_PASSWORD) - - @security_password.setter - def security_password(self, value): - """Set the password key.""" - self._data[ATTR_PASSWORD] = value - self.save() - - @property - def security_sessions(self): - """Return api sessions.""" - return { - session: parse_datetime(until) for - session, until in self._data[ATTR_SESSIONS].items() - } - - def add_security_session(self, session, valid): - """Set the a new session.""" - self._data[ATTR_SESSIONS].update( - {session: valid.isoformat()} - ) - self.save() - - def drop_security_session(self, session): - """Delete the a session.""" - self._data[ATTR_SESSIONS].pop(session, None) - self.save() - @property def audio_output(self): """Return ALSA audio output card,dev.""" diff --git a/hassio/const.py b/hassio/const.py index 6c8840f3a..ebf46b48e 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '0.81' +HASSIO_VERSION = '0.82' URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/' 'hassio/{}/version.json') diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index 760207143..e69512139 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -82,7 +82,7 @@ class DockerAddon(DockerInterface): # Set api token if any API access is needed if self.addon.access_hassio_api or self.addon.access_homeassistant_api: - addon_env['API_TOKEN'] = self.addon.api_token + addon_env['HASSIO_TOKEN'] = self.addon.uuid return { **addon_env, diff --git a/hassio/docker/homeassistant.py b/hassio/docker/homeassistant.py index 148e9c78e..9fff28172 100644 --- a/hassio/docker/homeassistant.py +++ b/hassio/docker/homeassistant.py @@ -54,6 +54,7 @@ class DockerHomeAssistant(DockerInterface): environment={ 'HASSIO': self._docker.network.supervisor, 'TZ': self._config.timezone, + 'HASSIO_TOKEN': self._homeassistant.uuid, }, volumes={ str(self._config.path_extern_config): diff --git a/hassio/docker/network.py b/hassio/docker/network.py index b4a57c79f..ee5a8b767 100644 --- a/hassio/docker/network.py +++ b/hassio/docker/network.py @@ -9,7 +9,10 @@ _LOGGER = logging.getLogger(__name__) class DockerNetwork(object): - """Internal HassIO Network.""" + """Internal HassIO Network. + + This class is not AsyncIO safe! + """ def __init__(self, dock): """Initialize internal hassio network.""" diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py index 6ee12289d..c36949e87 100644 --- a/hassio/homeassistant.py +++ b/hassio/homeassistant.py @@ -8,7 +8,7 @@ import aiohttp from aiohttp.hdrs import CONTENT_TYPE from .const import ( - FILE_HASSIO_HOMEASSISTANT, ATTR_IMAGE, ATTR_LAST_VERSION, + FILE_HASSIO_HOMEASSISTANT, ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_UUID, ATTR_BOOT, ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG, HEADER_HA_ACCESS, CONTENT_TYPE_JSON) from .coresys import CoreSysAttributes @@ -143,6 +143,11 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): """Set home-assistant boot options.""" self._data[ATTR_BOOT] = value + @property + def uuid(self): + """Return a UUID of this HomeAssistant.""" + return self._data[ATTR_UUID] + async def install_landingpage(self): """Install a landingpage.""" _LOGGER.info("Setup HomeAssistant landingpage") diff --git a/hassio/tasks.py b/hassio/tasks.py index 2ca22ef86..277064781 100644 --- a/hassio/tasks.py +++ b/hassio/tasks.py @@ -1,6 +1,5 @@ """Multible tasks.""" import asyncio -from datetime import datetime import logging from .coresys import CoreSysAttributes @@ -22,8 +21,6 @@ class Tasks(CoreSysAttributes): RUN_WATCHDOG_HOMEASSISTANT_DOCKER = 15 RUN_WATCHDOG_HOMEASSISTANT_API = 300 - RUN_CLEANUP_API_SESSIONS = 900 - def __init__(self, coresys): """Initialize Tasks.""" self.coresys = coresys @@ -55,13 +52,6 @@ class Tasks(CoreSysAttributes): _LOGGER.info("All core tasks are scheduled") - async def _cleanup_sessions(self): - """Cleanup old api sessions.""" - now = datetime.now() - for session, until_valid in self._config.security_sessions.items(): - if now >= until_valid: - self._config.drop_security_session(session) - async def _update_addons(self): """Check if a update is available of a addon and update it.""" tasks = [] diff --git a/hassio/validate.py b/hassio/validate.py index 4cd60ee43..71b843d81 100644 --- a/hassio/validate.py +++ b/hassio/validate.py @@ -1,14 +1,14 @@ """Validate functions.""" -import voluptuous as vol +import uuid +import voluptuous as vol import pytz from .const import ( - ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_SESSIONS, ATTR_PASSWORD, ATTR_TOTP, - ATTR_SECURITY, ATTR_BETA_CHANNEL, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST, - ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_HOMEASSISTANT, ATTR_HASSIO, - ATTR_BOOT, ATTR_LAST_BOOT, ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG, - ATTR_WAIT_BOOT) + ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_BETA_CHANNEL, ATTR_TIMEZONE, + ATTR_ADDONS_CUSTOM_LIST, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, + ATTR_PASSWORD, ATTR_HOMEASSISTANT, ATTR_HASSIO, ATTR_BOOT, ATTR_LAST_BOOT, + ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG, ATTR_WAIT_BOOT, ATTR_UUID) NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)) @@ -59,6 +59,8 @@ DOCKER_PORTS = vol.Schema({ # pylint: disable=no-value-for-parameter SCHEMA_HASS_CONFIG = vol.Schema({ + vol.Optional(ATTR_UUID, default=lambda: uuid.uuid4().hex): + vol.Match(r"^[0-9a-f]{32}$"), vol.Optional(ATTR_BOOT, default=True): vol.Boolean(), vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Coerce(str), vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'): vol.Coerce(str), @@ -84,11 +86,6 @@ SCHEMA_HASSIO_CONFIG = vol.Schema({ vol.Optional(ATTR_ADDONS_CUSTOM_LIST, default=[ "https://github.com/hassio-addons/repository", ]): [vol.Url()], - vol.Optional(ATTR_SECURITY, default=False): vol.Boolean(), - vol.Optional(ATTR_TOTP): vol.Coerce(str), - vol.Optional(ATTR_PASSWORD): vol.Coerce(str), - vol.Optional(ATTR_SESSIONS, default={}): - vol.Schema({vol.Coerce(str): vol.Coerce(str)}), vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_CHANNEL, vol.Optional(ATTR_AUDIO_INPUT): ALSA_CHANNEL, vol.Optional(ATTR_WAIT_BOOT, default=5): WAIT_BOOT, diff --git a/misc/hassio.png b/misc/hassio.png index 22c013125..3ccbf7ae9 100644 Binary files a/misc/hassio.png and b/misc/hassio.png differ diff --git a/misc/hassio.xml b/misc/hassio.xml index 42fa0b23c..685610ae1 100644 --- a/misc/hassio.xml +++ b/misc/hassio.xml @@ -1 +1 @@ -5Vptc6M2EP41/ng3gHj9mPiSy820c5n6Q3sfsVBsNTJyhYid/voKkABZkOBY+KYtmYnR6pVn99ld1l6A5e74laX77a80Q2ThOdlxAb4sPC8OY/G/Erw2At9xG8GG4awR9QQr/DeSQkdKS5yhQhvIKSUc73UhpHmOINdkKWP0oA97okTfdZ9ukCFYwZSY0t9xxrdS6oZJ1/GA8GYrt469sOlYp/B5w2iZy/0WHniqr6Z7l6q15IMW2zSjh54I3C3AklHKm7vdcYlIBa2CrZl3P9LbnpuhnE+Z4DUTXlJSInXikIipt09UrCAOyF8lKOFfJVUdn4paZTdigNjtKD5ERw206DtIYKrenLJdSrrJ4m5TfX5fqX3E2Zqtmg4JS7urd9hijlb7FFbtg7A2MWjLd0S03Oo0mJAlJZTVowXYKIRQyAvO6DPq9Tj1Jc+/kutLvF4Q4+g4CqHbKkbYO6I7xNmrGKImJKCZIm09SKRuD53l+Arobc9oQjkulca6aZfuFCZupM6G9QcM/X3LcaW31WvB0e5CNGGG1vF6CE0QggRkrb7sAhhNBNCzAKBvAPiFwmfELkUOokCQ/trI+SZy3hBywAJyoYHcw9JArXaFqJpRUe9MLscQDXN5HQd+4NjB0A8DHcPQxDBwTAgDCxAmBl4oE3FINinjW7qheUruOumtjmgPPXTE/I9K/DkKZPOH6srFwZq+QDV/yBX+RJy/ygiclpwKUbfxL5Tu5RrNUavzvQ20eBxaMihHRTJ4p2yDeM9uTHUwRFKOX/TVLwFX5RK20fXeQDcB3im+deMRMSweALGfBbp/JdCj0Xxi3UX48xIMN6wSjNMEYlXuEXvBhXAJagOm+h7Sovj2fTTBaMXr0aSjMwP3fbdluKflMgybVEN3aFmA4sy347ZAoLstMJB1uPGA33JtRE3Xm4Nbbo9Yyou13NJ4VbuxeUnkqveOHouiK7EIzOO6NHh1dE/iQtc89VyFwIPfVK9YQgCJYBqGSnyPidpzqm5QnpmLCWFvqcFMfrm0qlgvvlZQUm8cvaxJrPLpRjy6wLByU9dxRSmKn6CtLFR3Rd5A/t56HS1/9224ovDKXHE/O3qQ/+zG8aWBfiKtPmjxwLR4d0Sn1i3enyVUSJ30srCJCPYcTk5zpHmb8xQ2Vl+AJXtp+WpPYdeKPa5ZUrjJMpoXhhqLbbqvbveMQlQU73sn3ZVN9lX34qr9fZMTCt07XhiBxANhEHtx7PhgpqRqyJN5bmB6ssSCI1O1nDmJ0rVOHdWlqYAkU59uc7zoXEAAOfWR4vq9Q5WqneE0Wq3Q0FJO6hdSz1ynobKxTm0U7dNMs5PYJCjk1KxYKX6WO9IMALcVOzAUyKdrRB5pgTmmuRiyppzTnRhAqo7btoitVVbrMna3xg3Bm2oup+fRvCvEnpZu5QYWiHxS0wEDNR0wkJBYqciaNJ5AUifSWOq/x1LX5OgUOk5Ity8PgO97LQshEng/L0SqvXsMPBwOpvcmBO+LWg2SiZDQMrs4Tl6FQInuz3xnIKeP5iovgLcLo9K4P5DEn8mRmTLEXqzt3hyaQ3qj0faDNPFNmjTmaz+S+icmc+pN7YVAMP6tjfNQrkcjIUzZ5fQL62uAfkH1Z4d+CThJJ4boN1TdsxLBopnY17f7yGaWOT9lP8i+YAb2TVZjYJDkK+bbuekxFp2QmwUomocevnppvQo94v9LcEpCnaOR5dgU/idjk/m9+G9oX71qUYbReBXl30s+Vf6dgXyi2f0WqlFG93szcPcP \ No newline at end of file +5VrLcqM4FP0aLzsFiOcycefRVTPVqfFippdYKLYmMvII4cd8/QiQDEKQ4Bicnmp7Yevqybk691zJnoH55vDI4u36d5ogMnOs5DADX2eOY1vAER+F5VhZ3DCoDCuGE9moNizwv0j1lNYcJyjTGnJKCcdb3QhpmiLINVvMGN3rzV4o0WfdxitkGBYwJqb1T5zwtbTaflRXPCG8WsupQ8evKpYxfF0xmqdyvpkDXspXVb2J1VjyQbN1nNB9wwTuZ2DOKOXVt81hjkiBrYKt6vfQU3taN0MpH9JB+mkXkxypFftEdL17oWIEsUB+lKD4/+RUVXzJSpfdigZitoP4EBUl0KJuL4EpalPKNjGpO4tvq+Lz+0LNI9ZWTVVVSFhOszr7NeZosY1hUd6L7SYarfmGiJJdrAYTMqeEsrK1ABv5EAp7xhl9RY0aq3zJ9S/k+B14SdMOMY4ODZPE7xHRDeLsKJqo2ghUXeRe9yLp2329c1wF9LqxaXzZLpabdXUaunaY+CJ91u0/YPjvW4oLvy2OGUebC9GECVqGyy40gQ8ikJz8NS6AwUAAnREAdA0Av1L4itilyEHkCdJfGznXRM7pQg6MgJxvIPc0N1ArQyEqehTUO5PLIUTdXF6GnutZ42Do+p6OoW9i6FkmhN4IEEYGXigROiSLlPE1XdE0Jve19U5HtIEeOmD+V2G+CTxZ/KGqUrGwqs5TxR9yhL8R50epwHHOqTDVE/9G6VaO0Qt1RnMG5fKlyvOYrRDXtknxYG+6gyESc7zTBfgScFUuMTa6zhvoRiLxaeFbFp4Rw+IBELsS6O5ngR705hPLWuHPSzBsv0gw2gnEIt8itsOZCAlqAqbqnuIs+/a9N8E4mZe9SUe9Dez3w5YRnuZz369SDT2gJR4KE3ecsAU8PWyBjqzDDjvilj2GatrOFNyyG8RSUezELY1XZRgbSqJMMIPfFqcCYYBEbA4MlfkBE7WKQVyz1WmkQbbgs8gGpolwmhd0J7Tkoy62A9xAzIe6EKWJOZgwNobqTPjn80sc64Sfpl0qHjSSKzHKl1vx6ALDIppdJ2LFKHyBYyWresRyOtL8U3DS0nx3jIjlX5kr9o2l5wI3dhhemg8MpFWDLilNkcaVN9NmjRHAZITal9dnhDuJ4kifNZK5kRAe7tC+awqYs92Jzx922Kdpk2veTHzAgRoIvd4832d9InK52zrx/rjrrqE1pqduk4SmmeGvbB1vi69bRiHKsvd1RhelwarzIF6lcleHAMFSy/EDEDnA90InDC0XTJRFd2mSY3umJkUjSJK6vJsypNWltuRcmtTJsNck2Sgn2/FClez6THF50JQuV2ei9rlJjVDRUnZyGjfnZ45TUdkYp9wUp6cZtk9Ck6CQU/OKUvEz35CqAbgrqIChQD5eIvJMM8wxTUWTJeWcbkQDUlTcnX610K7Sy98t6jFuCV4VfTk9j+b1zXv7rl5OMAKRW5d4oOMSD3SklqNcwZs0HkBSK9BY6r7HUtvk6BA6XkXzztTxQYqofkH8KZIZtZgGA/f7vRm9CcHbrHSDZCIkNE8u1smrECjS45lrdZzOgqnuk8DbN+Fyc3/gOHYmRybK5RtaW58Bq0U6vWo7jCauSRO1WydXUre1ZdrRdDwJBP0/01lP+bJXCWHMLqefX7466OcV73HoF4FWOtFFv67r3FEULJiIfc19H4yZZU5P2WHs867BvsFu9AySPGK+npoefeqE7MRDwTT0cNWh9Sr0CH8VcYp8naPBZdrk/xraZP4R4g+0LY5alGHUf4vy/yWfusifgHyiWP/5rXJG/Q9DcP8f \ No newline at end of file diff --git a/misc/security.png b/misc/security.png deleted file mode 100644 index 8343b0e84..000000000 Binary files a/misc/security.png and /dev/null differ diff --git a/misc/security.xml b/misc/security.xml deleted file mode 100644 index 162e082f7..000000000 --- a/misc/security.xml +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/setup.py b/setup.py index 7b17c82c1..ac212a027 100644 --- a/setup.py +++ b/setup.py @@ -46,8 +46,6 @@ setup( 'colorlog', 'voluptuous', 'gitpython', - 'pyotp', - 'pyqrcode', 'pytz', 'pyudev' ] diff --git a/version.json b/version.json index 8352cb229..69f1a888e 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "hassio": "0.81", + "hassio": "0.82", "homeassistant": "0.61", "resinos": "1.1", "resinhup": "0.3",