2018-08-19 20:29:08 +00:00
|
|
|
"""Provide CORS support for the HTTP component."""
|
2021-05-10 21:30:47 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from typing import Final
|
|
|
|
|
2019-12-05 12:42:09 +00:00
|
|
|
from aiohttp.hdrs import ACCEPT, AUTHORIZATION, CONTENT_TYPE, ORIGIN
|
2021-05-10 21:30:47 +00:00
|
|
|
from aiohttp.web import Application
|
|
|
|
from aiohttp.web_urldispatcher import (
|
|
|
|
AbstractResource,
|
|
|
|
AbstractRoute,
|
|
|
|
Resource,
|
|
|
|
ResourceRoute,
|
|
|
|
StaticResource,
|
|
|
|
)
|
2018-02-15 21:06:14 +00:00
|
|
|
|
2019-10-14 21:56:45 +00:00
|
|
|
from homeassistant.const import HTTP_HEADER_X_REQUESTED_WITH
|
2018-02-15 21:06:14 +00:00
|
|
|
from homeassistant.core import callback
|
|
|
|
|
2021-05-10 21:30:47 +00:00
|
|
|
ALLOWED_CORS_HEADERS: Final[list[str]] = [
|
2019-07-31 19:25:30 +00:00
|
|
|
ORIGIN,
|
|
|
|
ACCEPT,
|
|
|
|
HTTP_HEADER_X_REQUESTED_WITH,
|
|
|
|
CONTENT_TYPE,
|
|
|
|
AUTHORIZATION,
|
|
|
|
]
|
2021-05-10 21:30:47 +00:00
|
|
|
VALID_CORS_TYPES: Final = (Resource, ResourceRoute, StaticResource)
|
2018-02-15 21:06:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
@callback
|
2021-05-10 21:30:47 +00:00
|
|
|
def setup_cors(app: Application, origins: list[str]) -> None:
|
2018-08-19 20:29:08 +00:00
|
|
|
"""Set up CORS."""
|
2019-10-19 19:44:51 +00:00
|
|
|
# This import should remain here. That way the HTTP integration can always
|
|
|
|
# be imported by other integrations without it's requirements being installed.
|
2019-12-05 12:42:09 +00:00
|
|
|
# pylint: disable=import-outside-toplevel
|
2019-10-19 19:44:51 +00:00
|
|
|
import aiohttp_cors
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
cors = aiohttp_cors.setup(
|
|
|
|
app,
|
|
|
|
defaults={
|
|
|
|
host: aiohttp_cors.ResourceOptions(
|
|
|
|
allow_headers=ALLOWED_CORS_HEADERS, allow_methods="*"
|
|
|
|
)
|
|
|
|
for host in origins
|
|
|
|
},
|
|
|
|
)
|
2018-02-15 21:06:14 +00:00
|
|
|
|
2018-07-25 09:36:44 +00:00
|
|
|
cors_added = set()
|
|
|
|
|
2021-05-10 21:30:47 +00:00
|
|
|
def _allow_cors(
|
|
|
|
route: AbstractRoute | AbstractResource,
|
|
|
|
config: dict[str, aiohttp_cors.ResourceOptions] | None = None,
|
|
|
|
) -> None:
|
2018-08-19 20:29:08 +00:00
|
|
|
"""Allow CORS on a route."""
|
2021-05-10 21:30:47 +00:00
|
|
|
if isinstance(route, AbstractRoute):
|
2018-07-25 09:36:44 +00:00
|
|
|
path = route.resource
|
|
|
|
else:
|
|
|
|
path = route
|
|
|
|
|
2019-06-03 18:43:13 +00:00
|
|
|
if not isinstance(path, VALID_CORS_TYPES):
|
|
|
|
return
|
|
|
|
|
2021-05-10 21:30:47 +00:00
|
|
|
path_str = path.canonical
|
2018-07-25 09:36:44 +00:00
|
|
|
|
2021-05-10 21:30:47 +00:00
|
|
|
if path_str.startswith("/api/hassio_ingress/"):
|
2019-08-05 06:24:54 +00:00
|
|
|
return
|
|
|
|
|
2021-05-10 21:30:47 +00:00
|
|
|
if path_str in cors_added:
|
2018-07-25 09:36:44 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
cors.add(route, config)
|
2021-05-10 21:30:47 +00:00
|
|
|
cors_added.add(path_str)
|
2018-07-19 06:37:00 +00:00
|
|
|
|
2021-11-09 17:30:51 +00:00
|
|
|
app["allow_all_cors"] = lambda route: _allow_cors(
|
2019-07-31 19:25:30 +00:00
|
|
|
route,
|
|
|
|
{
|
|
|
|
"*": aiohttp_cors.ResourceOptions(
|
|
|
|
allow_headers=ALLOWED_CORS_HEADERS, allow_methods="*"
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
2018-07-19 06:37:00 +00:00
|
|
|
|
2021-11-09 17:30:51 +00:00
|
|
|
if origins:
|
|
|
|
app["allow_configured_cors"] = _allow_cors
|
|
|
|
else:
|
|
|
|
app["allow_configured_cors"] = lambda _: None
|