Quote media_source paths (#49054)

* Quote path in async_sign_path

* Address review comments, add tests

* Update tests/testing_config/media/Epic Sax Guy 10 Hours.mp4

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
Erik Montnemery 2021-04-12 18:32:12 +02:00 committed by GitHub
parent dbb771e19c
commit f5545badac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 23 additions and 9 deletions

View File

@ -7,6 +7,7 @@ from datetime import timedelta
import functools as ft
import json
import logging
from urllib.parse import quote
import pychromecast
from pychromecast.controllers.homeassistant import HomeAssistantController
@ -472,7 +473,7 @@ class CastDevice(MediaPlayerEntity):
media_id = async_sign_path(
self.hass,
refresh_token.id,
media_id,
quote(media_id),
timedelta(seconds=media_source.DEFAULT_EXPIRY_TIME),
)

View File

@ -1,6 +1,7 @@
"""Authentication for HTTP component."""
import logging
import secrets
from urllib.parse import unquote
from aiohttp import hdrs
from aiohttp.web import middleware
@ -30,11 +31,16 @@ def async_sign_path(hass, refresh_token_id, path, expiration):
now = dt_util.utcnow()
encoded = jwt.encode(
{"iss": refresh_token_id, "path": path, "iat": now, "exp": now + expiration},
{
"iss": refresh_token_id,
"path": unquote(path),
"iat": now,
"exp": now + expiration,
},
secret,
algorithm="HS256",
)
return f"{path}?{SIGN_QUERY_PARAM}=" f"{encoded.decode()}"
return f"{path}?{SIGN_QUERY_PARAM}={encoded.decode()}"
@callback

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import timedelta
from urllib.parse import quote
import voluptuous as vol
@ -123,7 +124,7 @@ async def websocket_resolve_media(hass, connection, msg):
url = async_sign_path(
hass,
connection.refresh_token_id,
url,
quote(url),
timedelta(seconds=msg["expires"]),
)

View File

@ -1,5 +1,6 @@
"""Test Media Source initialization."""
from unittest.mock import patch
from urllib.parse import quote
import pytest
@ -45,7 +46,7 @@ async def test_async_browse_media(hass):
media = await media_source.async_browse_media(hass, "")
assert isinstance(media, media_source.models.BrowseMediaSource)
assert media.title == "media/"
assert len(media.children) == 1
assert len(media.children) == 2
# Test invalid media content
with pytest.raises(ValueError):
@ -133,14 +134,15 @@ async def test_websocket_browse_media(hass, hass_ws_client):
assert msg["error"]["message"] == "test"
async def test_websocket_resolve_media(hass, hass_ws_client):
@pytest.mark.parametrize("filename", ["test.mp3", "Epic Sax Guy 10 Hours.mp4"])
async def test_websocket_resolve_media(hass, hass_ws_client, filename):
"""Test browse media websocket."""
assert await async_setup_component(hass, const.DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
media = media_source.models.PlayMedia("/media/local/test.mp3", "audio/mpeg")
media = media_source.models.PlayMedia(f"/media/local/{filename}", "audio/mpeg")
with patch(
"homeassistant.components.media_source.async_resolve_media",
@ -150,7 +152,7 @@ async def test_websocket_resolve_media(hass, hass_ws_client):
{
"id": 1,
"type": "media_source/resolve_media",
"media_content_id": f"{const.URI_SCHEME}{const.DOMAIN}/local/test.mp3",
"media_content_id": f"{const.URI_SCHEME}{const.DOMAIN}/local/{filename}",
}
)
@ -158,7 +160,7 @@ async def test_websocket_resolve_media(hass, hass_ws_client):
assert msg["success"]
assert msg["id"] == 1
assert msg["result"]["url"].startswith(media.url)
assert msg["result"]["url"].startswith(quote(media.url))
assert msg["result"]["mime_type"] == media.mime_type
with patch(

View File

@ -95,5 +95,8 @@ async def test_media_view(hass, hass_client):
resp = await client.get("/media/local/test.mp3")
assert resp.status == 200
resp = await client.get("/media/local/Epic Sax Guy 10 Hours.mp4")
assert resp.status == 200
resp = await client.get("/media/recordings/test.mp3")
assert resp.status == 200

View File

@ -0,0 +1 @@
I play the sax