Use header URI in Plex config flow (#49915)

This commit is contained in:
jjlawren 2021-04-30 16:15:59 -05:00 committed by GitHub
parent a2138a7642
commit 37e8571fe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 79 deletions

View File

@ -10,6 +10,7 @@ import requests.exceptions
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import http
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.const import (
@ -25,7 +26,6 @@ from homeassistant.const import (
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.network import get_url
from .const import (
AUTH_CALLBACK_NAME,
@ -52,6 +52,8 @@ from .const import (
from .errors import NoServersFound, ServerNotSpecified
from .server import PlexServer
HEADER_FRONTEND_BASE = "HA-Frontend-Base"
_LOGGER = logging.getLogger(__package__)
@ -286,7 +288,11 @@ class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_plex_website_auth(self):
"""Begin external auth flow on Plex website."""
self.hass.http.register_view(PlexAuthorizationCallbackView)
hass_url = get_url(self.hass)
if (req := http.current_request.get()) is None:
raise RuntimeError("No current request in context")
if (hass_url := req.headers.get(HEADER_FRONTEND_BASE)) is None:
raise RuntimeError("No header in request")
headers = {"Origin": hass_url}
payload = {
"X-Plex-Device-Name": X_PLEX_DEVICE_NAME,

View File

@ -4,6 +4,7 @@ import ssl
from unittest.mock import patch
import plexapi.exceptions
import pytest
import requests.exceptions
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
@ -21,7 +22,6 @@ from homeassistant.components.plex.const import (
PLEX_SERVER_CONFIG,
SERVERS,
)
from homeassistant.config import async_process_ha_core_config
from homeassistant.config_entries import (
ENTRY_STATE_LOADED,
SOURCE_INTEGRATION_DISCOVERY,
@ -45,13 +45,8 @@ from .mock_classes import MockGDM
from tests.common import MockConfigEntry
async def test_bad_credentials(hass):
async def test_bad_credentials(hass, current_request_with_host):
"""Test when provided credentials are rejected."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -78,13 +73,8 @@ async def test_bad_credentials(hass):
assert result["errors"][CONF_TOKEN] == "faulty_credentials"
async def test_bad_hostname(hass, mock_plex_calls):
async def test_bad_hostname(hass, mock_plex_calls, current_request_with_host):
"""Test when an invalid address is provided."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -112,13 +102,8 @@ async def test_bad_hostname(hass, mock_plex_calls):
assert result["errors"][CONF_HOST] == "not_found"
async def test_unknown_exception(hass):
async def test_unknown_exception(hass, current_request_with_host):
"""Test when an unknown exception is encountered."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -141,15 +126,12 @@ async def test_unknown_exception(hass):
assert result["reason"] == "unknown"
async def test_no_servers_found(hass, mock_plex_calls, requests_mock, empty_payload):
async def test_no_servers_found(
hass, mock_plex_calls, requests_mock, empty_payload, current_request_with_host
):
"""Test when no servers are on an account."""
requests_mock.get("https://plex.tv/api/resources", text=empty_payload)
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -173,14 +155,10 @@ async def test_no_servers_found(hass, mock_plex_calls, requests_mock, empty_payl
assert result["errors"]["base"] == "no_servers"
async def test_single_available_server(hass, mock_plex_calls):
async def test_single_available_server(
hass, mock_plex_calls, current_request_with_host
):
"""Test creating an entry with one server available."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -217,15 +195,13 @@ async def test_single_available_server(hass, mock_plex_calls):
async def test_multiple_servers_with_selection(
hass, mock_plex_calls, requests_mock, plextv_resources_base
hass,
mock_plex_calls,
requests_mock,
plextv_resources_base,
current_request_with_host,
):
"""Test creating an entry with multiple servers available."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -273,15 +249,13 @@ async def test_multiple_servers_with_selection(
async def test_adding_last_unconfigured_server(
hass, mock_plex_calls, requests_mock, plextv_resources_base
hass,
mock_plex_calls,
requests_mock,
plextv_resources_base,
current_request_with_host,
):
"""Test automatically adding last unconfigured server when multiple servers on account."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
MockConfigEntry(
domain=DOMAIN,
data={
@ -331,15 +305,14 @@ async def test_adding_last_unconfigured_server(
async def test_all_available_servers_configured(
hass, entry, requests_mock, plextv_account, plextv_resources_base
hass,
entry,
requests_mock,
plextv_account,
plextv_resources_base,
current_request_with_host,
):
"""Test when all available servers are already configured."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
entry.add_to_hass(hass)
MockConfigEntry(
@ -470,14 +443,8 @@ async def test_option_flow_new_users_available(hass, entry, setup_plex_server):
assert "[New]" in multiselect_defaults[user]
async def test_external_timed_out(hass):
async def test_external_timed_out(hass, current_request_with_host):
"""Test when external flow times out."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -500,14 +467,8 @@ async def test_external_timed_out(hass):
assert result["reason"] == "token_request_timeout"
async def test_callback_view(hass, aiohttp_client):
async def test_callback_view(hass, aiohttp_client, current_request_with_host):
"""Test callback view."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -529,12 +490,8 @@ async def test_callback_view(hass, aiohttp_client):
assert resp.status == 200
async def test_manual_config(hass, mock_plex_calls):
async def test_manual_config(hass, mock_plex_calls, current_request_with_host):
"""Test creating via manual configuration."""
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
class WrongCertValidaitionException(requests.exceptions.SSLError):
"""Mock the exception showing an unmatched error."""
@ -744,13 +701,11 @@ async def test_integration_discovery(hass):
assert flow["step_id"] == "user"
async def test_trigger_reauth(hass, entry, mock_plex_server, mock_websocket):
async def test_trigger_reauth(
hass, entry, mock_plex_server, mock_websocket, current_request_with_host
):
"""Test setup and reauthorization of a Plex token."""
await async_setup_component(hass, "persistent_notification", {})
await async_process_ha_core_config(
hass,
{"internal_url": "http://example.local:8123"},
)
assert entry.state == ENTRY_STATE_LOADED
@ -791,3 +746,43 @@ async def test_trigger_reauth(hass, entry, mock_plex_server, mock_websocket):
assert entry.data[CONF_SERVER_IDENTIFIER] == mock_plex_server.machine_identifier
assert entry.data[PLEX_SERVER_CONFIG][CONF_URL] == PLEX_DIRECT_URL
assert entry.data[PLEX_SERVER_CONFIG][CONF_TOKEN] == "BRAND_NEW_TOKEN"
async def test_client_request_missing(hass):
"""Test when client headers are not set properly."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "user"
with patch("plexauth.PlexAuth.initiate_auth"), patch(
"plexauth.PlexAuth.token", return_value=None
):
with pytest.raises(RuntimeError):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
async def test_client_header_issues(hass, current_request_with_host):
"""Test when client headers are not set properly."""
class MockRequest:
headers = {}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "user"
with patch("plexauth.PlexAuth.initiate_auth"), patch(
"plexauth.PlexAuth.token", return_value=None
), patch(
"homeassistant.components.http.current_request.get", return_value=MockRequest()
):
with pytest.raises(RuntimeError):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)