예제 #1
0
def _get_deprecated_base_url(
    hass: HomeAssistant,
    *,
    internal: bool = False,
    allow_ip: bool = True,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Work with the deprecated `base_url`, used as fallback."""
    if hass.config.api is None or not hass.config.api.deprecated_base_url:
        raise NoURLAvailableError

    base_url = yarl.URL(hass.config.api.deprecated_base_url)
    # Rules that apply to both internal and external
    if ((allow_ip or not is_ip_address(str(base_url.host))) and
        (not require_current_request or base_url.host == _get_request_host())
            and (not require_ssl or base_url.scheme == "https")
            and (not require_standard_port or base_url.is_default_port())):
        # Check to ensure an internal URL
        if internal and (str(base_url.host).endswith(".local") or
                         (is_ip_address(str(base_url.host))
                          and not is_loopback(ip_address(base_url.host))
                          and is_private(ip_address(base_url.host)))):
            return normalize_url(str(base_url))

        # Check to ensure an external URL (a little)
        if (not internal and not str(base_url.host).endswith(".local")
                and not (is_ip_address(str(base_url.host))
                         and is_local(ip_address(str(base_url.host))))):
            return normalize_url(str(base_url))

    raise NoURLAvailableError
예제 #2
0
def _get_internal_url(
    hass: HomeAssistant,
    *,
    allow_ip: bool = True,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Get internal URL of this instance."""
    if hass.config.internal_url:
        internal_url = yarl.URL(hass.config.internal_url)
        if (
            (not require_current_request or internal_url.host == _get_request_host())
            and (not require_ssl or internal_url.scheme == "https")
            and (not require_standard_port or internal_url.is_default_port())
            and (allow_ip or not is_ip_address(str(internal_url.host)))
        ):
            return normalize_url(str(internal_url))

    # Fallback to detected local IP
    if allow_ip and not (
        require_ssl or hass.config.api is None or hass.config.api.use_ssl
    ):
        ip_url = yarl.URL.build(
            scheme="http", host=hass.config.api.local_ip, port=hass.config.api.port
        )
        if (
            not is_loopback(ip_address(ip_url.host))
            and (not require_current_request or ip_url.host == _get_request_host())
            and (not require_standard_port or ip_url.is_default_port())
        ):
            return normalize_url(str(ip_url))

    raise NoURLAvailableError
예제 #3
0
def _get_external_url(
    hass: HomeAssistant,
    *,
    allow_cloud: bool = True,
    allow_ip: bool = True,
    prefer_cloud: bool = False,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Get external URL of this instance."""
    if prefer_cloud and allow_cloud:
        with suppress(NoURLAvailableError):
            return _get_cloud_url(hass)

    if hass.config.external_url:
        external_url = yarl.URL(hass.config.external_url)
        if ((allow_ip or not is_ip_address(str(external_url.host)))
                and (not require_current_request
                     or external_url.host == _get_request_host()) and
            (not require_standard_port or external_url.is_default_port())
                and (not require_ssl or
                     (external_url.scheme == "https"
                      and not is_ip_address(str(external_url.host))))):
            return normalize_url(str(external_url))

    if allow_cloud:
        with suppress(NoURLAvailableError):
            return _get_cloud_url(
                hass, require_current_request=require_current_request)

    raise NoURLAvailableError
예제 #4
0
def _get_external_url(
    hass: HomeAssistant,
    *,
    allow_cloud: bool = True,
    allow_ip: bool = True,
    prefer_cloud: bool = False,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Get external URL of this instance."""
    if prefer_cloud and allow_cloud:
        try:
            return _get_cloud_url(hass)
        except NoURLAvailableError:
            pass

    if hass.config.external_url:
        external_url = yarl.URL(hass.config.external_url)
        if (
            (allow_ip or not is_ip_address(str(external_url.host)))
            and (
                not require_current_request or external_url.host == _get_request_host()
            )
            and (not require_standard_port or external_url.is_default_port())
            and (
                not require_ssl
                or (
                    external_url.scheme == "https"
                    and not is_ip_address(str(external_url.host))
                )
            )
        ):
            return normalize_url(str(external_url))

    try:
        return _get_deprecated_base_url(
            hass,
            allow_ip=allow_ip,
            require_current_request=require_current_request,
            require_ssl=require_ssl,
            require_standard_port=require_standard_port,
        )
    except NoURLAvailableError:
        pass

    if allow_cloud:
        try:
            return _get_cloud_url(hass, require_current_request=require_current_request)
        except NoURLAvailableError:
            pass
    # get ais url
    remote_access = hass.states.get("input_boolean.ais_remote_access").state
    if remote_access == "on":
        return hass.states.get("camera.remote_access").state
    else:
        return "http://" + hass.states.get("sensor.internal_ip_address").state + ":8180"

    raise NoURLAvailableError
예제 #5
0
파일: __init__.py 프로젝트: jcgoette/core
def valid_base_url(value: str) -> str:
    """Validate base url, return value."""
    url = yarl.URL(cv.url(value))

    if url.path != "/":
        raise vol.Invalid("Path should be empty")

    return normalize_url(value)
예제 #6
0
def _get_cloud_url(hass: HomeAssistant, require_current_request: bool = False) -> str:
    """Get external Home Assistant Cloud URL of this instance."""
    if "cloud" in hass.config.components:
        try:
            cloud_url = yarl.URL(cast(str, hass.components.cloud.async_remote_ui_url()))
        except hass.components.cloud.CloudNotAvailable as err:
            raise NoURLAvailableError from err

        if not require_current_request or cloud_url.host == _get_request_host():
            return normalize_url(str(cloud_url))

    raise NoURLAvailableError
예제 #7
0
def is_hass_url(hass: HomeAssistant, url: str) -> bool:
    """Return if the URL points at this Home Assistant instance."""
    parsed = yarl.URL(normalize_url(url))

    def host_ip() -> str | None:
        if hass.config.api is None or is_loopback(ip_address(hass.config.api.local_ip)):
            return None

        return str(
            yarl.URL.build(
                scheme="http", host=hass.config.api.local_ip, port=hass.config.api.port
            )
        )

    def cloud_url() -> str | None:
        try:
            return _get_cloud_url(hass)
        except NoURLAvailableError:
            return None

    for potential_base_factory in (
        lambda: hass.config.internal_url,
        lambda: hass.config.external_url,
        cloud_url,
        host_ip,
    ):
        potential_base = potential_base_factory()

        if potential_base is None:
            continue

        potential_parsed = yarl.URL(normalize_url(potential_base))

        if (
            parsed.scheme == potential_parsed.scheme
            and parsed.authority == potential_parsed.authority
        ):
            return True

    return False
예제 #8
0
파일: test_network.py 프로젝트: jbouwh/core
def test_normalize_url():
    """Test the normalizing of URLs."""
    assert network_util.normalize_url(
        "http://example.com") == "http://example.com"
    assert network_util.normalize_url(
        "https://example.com") == "https://example.com"
    assert network_util.normalize_url(
        "https://example.com/") == "https://example.com"
    assert (network_util.normalize_url("https://example.com:443") ==
            "https://example.com")
    assert network_util.normalize_url(
        "http://example.com:80") == "http://example.com"
    assert (network_util.normalize_url("https://example.com:80") ==
            "https://example.com:80")
    assert (network_util.normalize_url("http://example.com:443") ==
            "http://example.com:443")
    assert (network_util.normalize_url("https://example.com:443/test/") ==
            "https://example.com/test")
    assert network_util.normalize_url("/test/") == "/test"
예제 #9
0
파일: network.py 프로젝트: jcgoette/core
def is_hass_url(hass: HomeAssistant, url: str) -> bool:
    """Return if the URL points at this Home Assistant instance."""
    parsed = yarl.URL(url)

    if not parsed.is_absolute():
        return False

    if parsed.is_default_port():
        parsed = parsed.with_port(None)

    def host_ip() -> str | None:
        if hass.config.api is None or is_loopback(ip_address(hass.config.api.local_ip)):
            return None

        return str(
            yarl.URL.build(
                scheme="http", host=hass.config.api.local_ip, port=hass.config.api.port
            )
        )

    def cloud_url() -> str | None:
        try:
            return _get_cloud_url(hass)
        except NoURLAvailableError:
            return None

    potential_base_factory: Callable[[], str | None]
    for potential_base_factory in (
        lambda: hass.config.internal_url,
        lambda: hass.config.external_url,
        cloud_url,
        host_ip,
        lambda: get_supervisor_network_url(hass, allow_ssl=True),
    ):
        potential_base = potential_base_factory()

        if potential_base is None:
            continue

        potential_parsed = yarl.URL(normalize_url(potential_base))

        if (
            parsed.scheme == potential_parsed.scheme
            and parsed.authority == potential_parsed.authority
        ):
            return True

    return False
예제 #10
0
def _get_external_url(
    hass: HomeAssistant,
    *,
    allow_cloud: bool = True,
    allow_ip: bool = True,
    prefer_cloud: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Get external URL of this instance."""
    if prefer_cloud and allow_cloud:
        try:
            return _get_cloud_url(hass)
        except NoURLAvailableError:
            pass

    if hass.config.external_url:
        external_url = yarl.URL(hass.config.external_url)
        if (
            (allow_ip or not is_ip_address(str(external_url.host)))
            and (not require_standard_port or external_url.is_default_port())
            and (
                not require_ssl
                or (
                    external_url.scheme == "https"
                    and not is_ip_address(str(external_url.host))
                )
            )
        ):
            return normalize_url(str(external_url))

    try:
        return _get_deprecated_base_url(
            hass,
            allow_ip=allow_ip,
            require_ssl=require_ssl,
            require_standard_port=require_standard_port,
        )
    except NoURLAvailableError:
        pass

    if allow_cloud:
        try:
            return _get_cloud_url(hass)
        except NoURLAvailableError:
            pass

    raise NoURLAvailableError
예제 #11
0
def _get_external_url(
    hass: HomeAssistant,
    *,
    allow_cloud: bool = True,
    allow_ip: bool = True,
    prefer_cloud: bool = False,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
) -> str:
    """Get external URL of this instance."""
    if prefer_cloud and allow_cloud:
        with suppress(NoURLAvailableError):
            return _get_cloud_url(hass)

    if hass.config.external_url:
        external_url = yarl.URL(hass.config.external_url)
        if ((allow_ip or not is_ip_address(str(external_url.host)))
                and (not require_current_request
                     or external_url.host == _get_request_host()) and
            (not require_standard_port or external_url.is_default_port())
                and (not require_ssl or
                     (external_url.scheme == "https"
                      and not is_ip_address(str(external_url.host))))):
            return normalize_url(str(external_url))

    if allow_cloud:
        with suppress(NoURLAvailableError):
            return _get_cloud_url(
                hass, require_current_request=require_current_request)

    # get ais url
    remote_access = hass.states.get("input_boolean.ais_remote_access").state
    if remote_access == "on":
        import homeassistant.components.ais_dom.ais_global as ais_global

        return "https://" + ais_global.get_sercure_android_id_dom(
        ) + ".paczka.pro"
    else:
        return "http://" + hass.config.api.local_ip + ":" + str(
            hass.config.api.port)

    raise NoURLAvailableError
예제 #12
0
def get_url(
    hass: HomeAssistant,
    *,
    require_current_request: bool = False,
    require_ssl: bool = False,
    require_standard_port: bool = False,
    allow_internal: bool = True,
    allow_external: bool = True,
    allow_cloud: bool = True,
    allow_ip: bool = True,
    prefer_external: bool = False,
    prefer_cloud: bool = False,
) -> str:
    """Get a URL to this instance."""
    if require_current_request and http.current_request.get() is None:
        raise NoURLAvailableError

    order = [TYPE_URL_INTERNAL, TYPE_URL_EXTERNAL]
    if prefer_external:
        order.reverse()

    # Try finding an URL in the order specified
    for url_type in order:

        if allow_internal and url_type == TYPE_URL_INTERNAL:
            try:
                return _get_internal_url(
                    hass,
                    allow_ip=allow_ip,
                    require_current_request=require_current_request,
                    require_ssl=require_ssl,
                    require_standard_port=require_standard_port,
                )
            except NoURLAvailableError:
                pass

        if allow_external and url_type == TYPE_URL_EXTERNAL:
            try:
                return _get_external_url(
                    hass,
                    allow_cloud=allow_cloud,
                    allow_ip=allow_ip,
                    prefer_cloud=prefer_cloud,
                    require_current_request=require_current_request,
                    require_ssl=require_ssl,
                    require_standard_port=require_standard_port,
                )
            except NoURLAvailableError:
                pass

    # For current request, we accept loopback interfaces (e.g., 127.0.0.1),
    # the Supervisor hostname and localhost transparently
    request_host = _get_request_host()
    if (
        require_current_request
        and request_host is not None
        and hass.config.api is not None
    ):
        scheme = "https" if hass.config.api.use_ssl else "http"
        current_url = yarl.URL.build(
            scheme=scheme, host=request_host, port=hass.config.api.port
        )

        known_hostnames = ["localhost"]
        if hass.components.hassio.is_hassio():
            host_info = hass.components.hassio.get_host_info()
            known_hostnames.extend(
                [host_info["hostname"], f"{host_info['hostname']}.local"]
            )

        if (
            (
                (
                    allow_ip
                    and is_ip_address(request_host)
                    and is_loopback(ip_address(request_host))
                )
                or request_host in known_hostnames
            )
            and (not require_ssl or current_url.scheme == "https")
            and (not require_standard_port or current_url.is_default_port())
        ):
            return normalize_url(str(current_url))

    # We have to be honest now, we have no viable option available
    raise NoURLAvailableError
예제 #13
0
def test_valid_base_url(value):
    """Test we validate base urls."""
    assert tts.valid_base_url(value) == normalize_url(value)
    # Test we strip trailing `/`
    assert tts.valid_base_url(value + "/") == normalize_url(value)