Skip to main content

A library to proxy web traffic through Home Assistant integrations.

Project description

hass-web-proxy-lib

A small Home Assistant library to proxy web traffic through Home Assistant. Used by the Home Assistant Web Proxy Integration and any other integration that needs to proxy traffic through Home Assistant.

This library is not itself an integration but rather can be used by integration developers to offer proxying capabilities within their own integration.

Usage

Use this library as part of your custom integration by declaring a new HomeAssistantView that inherits from the ProxyView or WebsocketProxyView class in this library. Callers must implement the _get_proxied_url method to return a ProxiedURL object containing a destination URL for a given proxy request, or raising an exception to indicate an error condition.

Example Usage

Proxies a GET request from https://$HA_INSTANCE/api/my_integration/proxy/ through to /dir/file relative to the URL stored in the config entry data.

@callback
async def async_setup_entry(hass: HomeAssistant) -> None:
    """Set up the HASS web proxy entry."""
    session = async_get_clientsession(hass)
    hass.http.register_view(MyProxyView(hass, session))


class MyProxyView(ProxyView):
    """A proxy view for My Integration."""

    url = "/api/my_integration/proxy/"
    name = "api:my_integration:proxy"

    def _get_proxied_url(self, request: web.Request) -> ProxiedURL:
        """Get the URL to proxy."""
        # Retrieve host to connect to from config entry data.
        # Specifics depend on your application, this is an example only.
        config_entries = hass.config_entries.async_entries(DOMAIN):
        if not config_entries:
            raise HASSWebProxyLibNotFoundRequestError
        url = config_entries[0].data.get(CONF_URL)
        if not url:
            raise HASSWebProxyLibNotFoundRequestError
        return ProxiedURL(url=f"${url}/dir/file")

See the hass-web-proxy-integration for a more complete example of usage of this library.

Key Classes

ProxyView

The main class to inherit from for simple GET request proxying. Inheritors must implement _get_proxied_url(...) to return a ProxiedURL object.

WebsocketProxyView

The class to inherit from for websocket proxying. Inheritors must implement _get_proxied_url(...) to return a ProxiedURL object.

ProxiedURL

A small dataclass returned by overridden _get_proxied_url(...) methods that describes how the library should proxy a given request.

Field name Default Description
url The destination URL a given request should be made to, e.g. https://my-backend.my-domain.io.
allow_unauthenticated False When False or unset, unauthenticated HA traffic will be rejected with a 401 Unauthorized status. When True, unauthenticated traffic will be allowed.
headers An optional dictionary of headers to set on the outbound request.
query_params An optional dictionary of query parameters to set in the target URL. This is a convenience alternative to the caller simply adding the query string parameters onto the url parameter.
ssl_context An optional SSLContext object that should be used for secure onward requests.

Errors

HASSWebProxyLibBadRequestError

Can be raised by _get_proxied_url(...) to indicate a bad request (400 Bad Request).

HASSWebProxyLibUnauthorizedRequestError

Can be raised by _get_proxied_url(...) to indicate an unauthorized request (401 Unauthorized).

HASSWebProxyLibForbiddenRequestError

Can be raised by _get_proxied_url(...) to indicate a forbidden request (403 Forbidden).

HASSWebProxyLibNotFoundRequestError

Can be raised by _get_proxied_url(...) to indicate a request is not found request (404 Not Found).

HASSWebProxyLibExpiredError

Can be raised by _get_proxied_url(...) to indicate an expired / permanently removed resource is not available (410 Gone).

Testing

This library also contains a small test utility and fixture file that can be used to test proxying.

Test Handlers

response_handler(request: web.Request) -> web.Response

A small response handler that will return a json object containing:

Field name Description
headers A dictionary of the request headers received.
url The full URL/querystring requested.

ws_response_handler(request: web.Request) -> web.WebSocketResponse

A small websocket response handler that will initially return a json object containing headers and url (as in response_handler above), and then will simply echo back any future text or binary data.

Test Fixtures

The local_server fixture will start a small aiohttp server that can be "proxied to". The server listens to / and /ws for simple GET requests and websockets respectively using the above handlers. The resultant server address will be available within the local_server variable as a URL object.

Example Test Usage

import pytest
from hass_web_proxy_lib.tests.utils import response_handler, ws_response_handler

# Add the HA and local_server fixtures.
pytest_plugins = [
    "pytest_homeassistant_custom_component",
]

# Start a server that listens to requests for /dir/file and /dir/websocket .
@pytest.fixture
async def local_backend(hass: HomeAssistant, aiohttp_server: Any) -> Any:
    """Start a local backend."""

    # Start a local backend.
    app = web.Application()
    app.add_routes([
        web.get("/dir/file", response_handler),
        web.get("/dir/websocket", ws_response_handler),

    ])

    # Create a config entry for my integration, passing in the local backend
    # address as config entry data.
    config_entry: MockConfigEntry = MockConfigEntry(
        entry_id="74565ad414754616000674c87bdc876c",
        domain=DOMAIN,
        data={CONF_URL: str(app.make_url("/"))},
        title="My entry"
    )
    config_entry.add_to_hass(hass)

    # Setup the integration.
    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    return await aiohttp_server(app)


async def test_proxy_view_success(
    hass: HomeAssistant,
    local_backend: Any,
    hass_client: Any,
) -> None:
    """Test that a valid URL proxies successfully."""
    authenticated_hass_client = await hass_client()
    # The proxy code above in `_get_proxied_url` should result in a request to
    # $URL/dir/file which should return an OK HTTP status.
    resp = await authenticated_hass_client.get(f"/api/my_integration/proxy/")
    assert resp.status == HTTPStatus.OK

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hass_web_proxy_lib-0.0.7.tar.gz (13.1 kB view details)

Uploaded Source

Built Distribution

hass_web_proxy_lib-0.0.7-py3-none-any.whl (12.9 kB view details)

Uploaded Python 3

File details

Details for the file hass_web_proxy_lib-0.0.7.tar.gz.

File metadata

  • Download URL: hass_web_proxy_lib-0.0.7.tar.gz
  • Upload date:
  • Size: 13.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.12.7 Linux/5.4.0-196-generic

File hashes

Hashes for hass_web_proxy_lib-0.0.7.tar.gz
Algorithm Hash digest
SHA256 6e1cfbd6d34ea59fb8b52967752f946c2df0d965b9f9d00cb6993b4e79c5a6e4
MD5 be20caffeb4f9cc65f75e0f820a5bc16
BLAKE2b-256 b5ee130cb57fb852524e73a16f5b422b09dae60cd26ca8ebd0fac645bb99e74b

See more details on using hashes here.

File details

Details for the file hass_web_proxy_lib-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: hass_web_proxy_lib-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 12.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.12.7 Linux/5.4.0-196-generic

File hashes

Hashes for hass_web_proxy_lib-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 98250b4cdd5543ed3a8bf172bfc70f2698ca3a9d18b223bb6f7afebb87ffa55f
MD5 6ebc659bc15382bcca87efecbbcec8c4
BLAKE2b-256 e0012512288bb73820fa93e119449ee9dfa1a74921db56e238448b7d171cb67b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page