mirror of
https://github.com/home-assistant/core.git
synced 2025-04-28 19:27:51 +00:00
Fix alexa flash briefings after removal of api_password auth (#36789)
This commit is contained in:
parent
835f433cf7
commit
2c7876fa66
@ -17,6 +17,7 @@ from .const import (
|
|||||||
CONF_ENTITY_CONFIG,
|
CONF_ENTITY_CONFIG,
|
||||||
CONF_FILTER,
|
CONF_FILTER,
|
||||||
CONF_LOCALE,
|
CONF_LOCALE,
|
||||||
|
CONF_PASSWORD,
|
||||||
CONF_SUPPORTED_LOCALES,
|
CONF_SUPPORTED_LOCALES,
|
||||||
CONF_TEXT,
|
CONF_TEXT,
|
||||||
CONF_TITLE,
|
CONF_TITLE,
|
||||||
@ -56,6 +57,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
{
|
{
|
||||||
DOMAIN: {
|
DOMAIN: {
|
||||||
CONF_FLASH_BRIEFINGS: {
|
CONF_FLASH_BRIEFINGS: {
|
||||||
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
cv.string: vol.All(
|
cv.string: vol.All(
|
||||||
cv.ensure_list,
|
cv.ensure_list,
|
||||||
[
|
[
|
||||||
@ -67,7 +69,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(CONF_DISPLAY_URL): cv.template,
|
vol.Optional(CONF_DISPLAY_URL): cv.template,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
# vol.Optional here would mean we couldn't distinguish between an empty
|
# vol.Optional here would mean we couldn't distinguish between an empty
|
||||||
# smart_home: and none at all.
|
# smart_home: and none at all.
|
||||||
|
@ -19,6 +19,7 @@ CONF_FILTER = "filter"
|
|||||||
CONF_ENTITY_CONFIG = "entity_config"
|
CONF_ENTITY_CONFIG = "entity_config"
|
||||||
CONF_ENDPOINT = "endpoint"
|
CONF_ENDPOINT = "endpoint"
|
||||||
CONF_LOCALE = "locale"
|
CONF_LOCALE = "locale"
|
||||||
|
CONF_PASSWORD = "password"
|
||||||
|
|
||||||
ATTR_UID = "uid"
|
ATTR_UID = "uid"
|
||||||
ATTR_UPDATE_DATE = "updateDate"
|
ATTR_UPDATE_DATE = "updateDate"
|
||||||
@ -39,6 +40,7 @@ API_HEADER = "header"
|
|||||||
API_PAYLOAD = "payload"
|
API_PAYLOAD = "payload"
|
||||||
API_SCOPE = "scope"
|
API_SCOPE = "scope"
|
||||||
API_CHANGE = "change"
|
API_CHANGE = "change"
|
||||||
|
API_PASSWORD = "password"
|
||||||
|
|
||||||
CONF_DESCRIPTION = "description"
|
CONF_DESCRIPTION = "description"
|
||||||
CONF_DISPLAY_CATEGORIES = "display_categories"
|
CONF_DISPLAY_CATEGORIES = "display_categories"
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
"""Support for Alexa skill service end point."""
|
"""Support for Alexa skill service end point."""
|
||||||
import copy
|
import copy
|
||||||
|
import hmac
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from homeassistant.components import http
|
from homeassistant.components import http
|
||||||
from homeassistant.const import HTTP_NOT_FOUND
|
from homeassistant.const import HTTP_NOT_FOUND, HTTP_UNAUTHORIZED
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import template
|
from homeassistant.helpers import template
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
API_PASSWORD,
|
||||||
ATTR_MAIN_TEXT,
|
ATTR_MAIN_TEXT,
|
||||||
ATTR_REDIRECTION_URL,
|
ATTR_REDIRECTION_URL,
|
||||||
ATTR_STREAM_URL,
|
ATTR_STREAM_URL,
|
||||||
@ -18,6 +20,7 @@ from .const import (
|
|||||||
ATTR_UPDATE_DATE,
|
ATTR_UPDATE_DATE,
|
||||||
CONF_AUDIO,
|
CONF_AUDIO,
|
||||||
CONF_DISPLAY_URL,
|
CONF_DISPLAY_URL,
|
||||||
|
CONF_PASSWORD,
|
||||||
CONF_TEXT,
|
CONF_TEXT,
|
||||||
CONF_TITLE,
|
CONF_TITLE,
|
||||||
CONF_UID,
|
CONF_UID,
|
||||||
@ -39,6 +42,7 @@ class AlexaFlashBriefingView(http.HomeAssistantView):
|
|||||||
"""Handle Alexa Flash Briefing skill requests."""
|
"""Handle Alexa Flash Briefing skill requests."""
|
||||||
|
|
||||||
url = FLASH_BRIEFINGS_API_ENDPOINT
|
url = FLASH_BRIEFINGS_API_ENDPOINT
|
||||||
|
requires_auth = False
|
||||||
name = "api:alexa:flash_briefings"
|
name = "api:alexa:flash_briefings"
|
||||||
|
|
||||||
def __init__(self, hass, flash_briefings):
|
def __init__(self, hass, flash_briefings):
|
||||||
@ -52,7 +56,20 @@ class AlexaFlashBriefingView(http.HomeAssistantView):
|
|||||||
"""Handle Alexa Flash Briefing request."""
|
"""Handle Alexa Flash Briefing request."""
|
||||||
_LOGGER.debug("Received Alexa flash briefing request for: %s", briefing_id)
|
_LOGGER.debug("Received Alexa flash briefing request for: %s", briefing_id)
|
||||||
|
|
||||||
if self.flash_briefings.get(briefing_id) is None:
|
if request.query.get(API_PASSWORD) is None:
|
||||||
|
err = "No password provided for Alexa flash briefing: %s"
|
||||||
|
_LOGGER.error(err, briefing_id)
|
||||||
|
return b"", HTTP_UNAUTHORIZED
|
||||||
|
|
||||||
|
if not hmac.compare_digest(
|
||||||
|
request.query[API_PASSWORD].encode("utf-8"),
|
||||||
|
self.flash_briefings[CONF_PASSWORD].encode("utf-8"),
|
||||||
|
):
|
||||||
|
err = "Wrong password for Alexa flash briefing: %s"
|
||||||
|
_LOGGER.error(err, briefing_id)
|
||||||
|
return b"", HTTP_UNAUTHORIZED
|
||||||
|
|
||||||
|
if not isinstance(self.flash_briefings.get(briefing_id), list):
|
||||||
err = "No configured Alexa flash briefing was found for: %s"
|
err = "No configured Alexa flash briefing was found for: %s"
|
||||||
_LOGGER.error(err, briefing_id)
|
_LOGGER.error(err, briefing_id)
|
||||||
return b"", HTTP_NOT_FOUND
|
return b"", HTTP_NOT_FOUND
|
||||||
|
@ -6,7 +6,7 @@ import pytest
|
|||||||
|
|
||||||
from homeassistant.components import alexa
|
from homeassistant.components import alexa
|
||||||
from homeassistant.components.alexa import const
|
from homeassistant.components.alexa import const
|
||||||
from homeassistant.const import HTTP_NOT_FOUND
|
from homeassistant.const import HTTP_NOT_FOUND, HTTP_UNAUTHORIZED
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
@ -39,6 +39,7 @@ def alexa_client(loop, hass, hass_client):
|
|||||||
"homeassistant": {},
|
"homeassistant": {},
|
||||||
"alexa": {
|
"alexa": {
|
||||||
"flash_briefings": {
|
"flash_briefings": {
|
||||||
|
"password": "pass/abc",
|
||||||
"weather": [
|
"weather": [
|
||||||
{
|
{
|
||||||
"title": "Weekly forecast",
|
"title": "Weekly forecast",
|
||||||
@ -63,9 +64,12 @@ def alexa_client(loop, hass, hass_client):
|
|||||||
return loop.run_until_complete(hass_client())
|
return loop.run_until_complete(hass_client())
|
||||||
|
|
||||||
|
|
||||||
def _flash_briefing_req(client, briefing_id):
|
def _flash_briefing_req(client, briefing_id, password="pass%2Fabc"):
|
||||||
|
if password is None:
|
||||||
return client.get(f"/api/alexa/flash_briefings/{briefing_id}")
|
return client.get(f"/api/alexa/flash_briefings/{briefing_id}")
|
||||||
|
|
||||||
|
return client.get(f"/api/alexa/flash_briefings/{briefing_id}?password={password}")
|
||||||
|
|
||||||
|
|
||||||
async def test_flash_briefing_invalid_id(alexa_client):
|
async def test_flash_briefing_invalid_id(alexa_client):
|
||||||
"""Test an invalid Flash Briefing ID."""
|
"""Test an invalid Flash Briefing ID."""
|
||||||
@ -75,6 +79,30 @@ async def test_flash_briefing_invalid_id(alexa_client):
|
|||||||
assert text == ""
|
assert text == ""
|
||||||
|
|
||||||
|
|
||||||
|
async def test_flash_briefing_no_password(alexa_client):
|
||||||
|
"""Test for no Flash Briefing password."""
|
||||||
|
req = await _flash_briefing_req(alexa_client, "weather", password=None)
|
||||||
|
assert req.status == HTTP_UNAUTHORIZED
|
||||||
|
text = await req.text()
|
||||||
|
assert text == ""
|
||||||
|
|
||||||
|
|
||||||
|
async def test_flash_briefing_invalid_password(alexa_client):
|
||||||
|
"""Test an invalid Flash Briefing password."""
|
||||||
|
req = await _flash_briefing_req(alexa_client, "weather", password="wrongpass")
|
||||||
|
assert req.status == HTTP_UNAUTHORIZED
|
||||||
|
text = await req.text()
|
||||||
|
assert text == ""
|
||||||
|
|
||||||
|
|
||||||
|
async def test_flash_briefing_request_for_password(alexa_client):
|
||||||
|
"""Test for "password" Flash Briefing."""
|
||||||
|
req = await _flash_briefing_req(alexa_client, "password")
|
||||||
|
assert req.status == HTTP_NOT_FOUND
|
||||||
|
text = await req.text()
|
||||||
|
assert text == ""
|
||||||
|
|
||||||
|
|
||||||
async def test_flash_briefing_date_from_str(alexa_client):
|
async def test_flash_briefing_date_from_str(alexa_client):
|
||||||
"""Test the response has a valid date parsed from string."""
|
"""Test the response has a valid date parsed from string."""
|
||||||
req = await _flash_briefing_req(alexa_client, "weather")
|
req = await _flash_briefing_req(alexa_client, "weather")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user