mirror of
https://github.com/esphome/esphome.git
synced 2026-10-05 18:41:32 +00:00
Trim the noise glue and drive the source filter from the define
This commit is contained in:
@@ -11,6 +11,7 @@ import asyncio
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
import functools
|
||||
from pathlib import Path
|
||||
import socket
|
||||
|
||||
import pytest
|
||||
@@ -22,6 +23,7 @@ from .const import LOCALHOST, PORT_POLL_INTERVAL, PORT_WAIT_TIMEOUT
|
||||
from .types import CompileFunction, ConfigWriter
|
||||
|
||||
DEVICE_NAME = "host-ota-test"
|
||||
API_KEY = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -121,7 +123,6 @@ async def test_host_ota_encrypted(
|
||||
) -> None:
|
||||
"""Encrypted self-OTA succeeds; a plaintext upload to the same device fails."""
|
||||
pytest.importorskip("aioesphomeapi.noise")
|
||||
noise_psk = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
api_port, api_socket = reserved_tcp_port
|
||||
with _reserve_port() as (ota_port, ota_socket):
|
||||
yaml_config = yaml_config.replace("__OTA_PORT__", str(ota_port))
|
||||
@@ -158,7 +159,7 @@ async def test_host_ota_encrypted(
|
||||
ota_port,
|
||||
None,
|
||||
binary_path,
|
||||
noise_psk=noise_psk,
|
||||
noise_psk=API_KEY,
|
||||
),
|
||||
)
|
||||
assert rc == 0, "encrypted OTA reported failure"
|
||||
@@ -187,61 +188,22 @@ class _RebootCounter:
|
||||
await self._seen.wait()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_host_ota_api_key_offers_encryption(
|
||||
yaml_config: str,
|
||||
write_yaml_config: ConfigWriter,
|
||||
compile_esphome: CompileFunction,
|
||||
reserved_tcp_port: tuple[int, socket.socket],
|
||||
) -> None:
|
||||
"""With only an api key the device takes both a plaintext upload and an
|
||||
encrypted one using that key, which is the enablement path for
|
||||
`ota: encryption:`."""
|
||||
pytest.importorskip("aioesphomeapi.noise")
|
||||
api_key = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
api_port, api_socket = reserved_tcp_port
|
||||
with _reserve_port() as (ota_port, ota_socket):
|
||||
yaml_config = yaml_config.replace("__OTA_PORT__", str(ota_port))
|
||||
config_path = await write_yaml_config(yaml_config)
|
||||
binary_path = await compile_esphome(config_path)
|
||||
api_socket.close()
|
||||
ota_socket.close()
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
reboots = _RebootCounter()
|
||||
|
||||
async with run_binary(binary_path, line_callback=reboots.on_log) as (
|
||||
proc,
|
||||
lines,
|
||||
):
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
pid_before = proc.pid
|
||||
|
||||
rc, _ = await loop.run_in_executor(
|
||||
None, espota2.run_ota, LOCALHOST, ota_port, None, binary_path
|
||||
)
|
||||
assert rc == 0, "plaintext upload to an offering device must succeed"
|
||||
await reboots.wait(1)
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
assert proc.pid == pid_before
|
||||
|
||||
rc, _ = await loop.run_in_executor(
|
||||
None,
|
||||
functools.partial(
|
||||
espota2.run_ota,
|
||||
LOCALHOST,
|
||||
ota_port,
|
||||
None,
|
||||
binary_path,
|
||||
noise_psk=api_key,
|
||||
),
|
||||
)
|
||||
assert rc == 0, "encrypted upload with the api key must succeed"
|
||||
await reboots.wait(2)
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
assert proc.returncode is None, "process exited instead of execing"
|
||||
assert proc.pid == pid_before
|
||||
assert any("Encryption: offered" in line for line in lines)
|
||||
async def _run_ota(
|
||||
ota_port: int, password: str | None, binary_path: Path, noise_psk: str | None
|
||||
) -> int:
|
||||
"""espota2 is blocking; run it in the executor and return its exit code."""
|
||||
rc, _ = await asyncio.get_running_loop().run_in_executor(
|
||||
None,
|
||||
functools.partial(
|
||||
espota2.run_ota,
|
||||
LOCALHOST,
|
||||
ota_port,
|
||||
password,
|
||||
binary_path,
|
||||
noise_psk=noise_psk,
|
||||
),
|
||||
)
|
||||
return rc
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -251,10 +213,11 @@ async def test_host_ota_api_key_offer_with_password(
|
||||
compile_esphome: CompileFunction,
|
||||
reserved_tcp_port: tuple[int, socket.socket],
|
||||
) -> None:
|
||||
"""The OTA password still guards plaintext uploads on an offering device
|
||||
while the api key alone authenticates an encrypted one."""
|
||||
"""With only an api key the device offers encryption without requiring
|
||||
it: the password still guards plaintext uploads, and the key alone
|
||||
authenticates an encrypted one, which is the enablement path for
|
||||
`ota: encryption:`."""
|
||||
pytest.importorskip("aioesphomeapi.noise")
|
||||
api_key = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
api_port, api_socket = reserved_tcp_port
|
||||
with _reserve_port() as (ota_port, ota_socket):
|
||||
yaml_config = yaml_config.replace("__OTA_PORT__", str(ota_port))
|
||||
@@ -263,46 +226,32 @@ async def test_host_ota_api_key_offer_with_password(
|
||||
api_socket.close()
|
||||
ota_socket.close()
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
reboots = _RebootCounter()
|
||||
|
||||
async with run_binary(binary_path, line_callback=reboots.on_log) as (
|
||||
proc,
|
||||
_lines,
|
||||
lines,
|
||||
):
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
pid_before = proc.pid
|
||||
|
||||
rc, _ = await loop.run_in_executor(
|
||||
None, espota2.run_ota, LOCALHOST, ota_port, None, binary_path
|
||||
)
|
||||
rc = await _run_ota(ota_port, None, binary_path, None)
|
||||
assert rc == 1, "plaintext upload without the password must fail"
|
||||
await asyncio.sleep(0.5)
|
||||
assert proc.returncode is None, "process died on rejected upload"
|
||||
|
||||
rc, _ = await loop.run_in_executor(
|
||||
None, espota2.run_ota, LOCALHOST, ota_port, "hunter2", binary_path
|
||||
)
|
||||
rc = await _run_ota(ota_port, "hunter2", binary_path, None)
|
||||
assert rc == 0, "plaintext upload with the password must succeed"
|
||||
await reboots.wait(1)
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
assert proc.pid == pid_before
|
||||
|
||||
rc, _ = await loop.run_in_executor(
|
||||
None,
|
||||
functools.partial(
|
||||
espota2.run_ota,
|
||||
LOCALHOST,
|
||||
ota_port,
|
||||
None,
|
||||
binary_path,
|
||||
noise_psk=api_key,
|
||||
),
|
||||
)
|
||||
rc = await _run_ota(ota_port, None, binary_path, API_KEY)
|
||||
assert rc == 0, "encrypted upload with the api key must succeed"
|
||||
await reboots.wait(2)
|
||||
await _wait_for_port(LOCALHOST, api_port, PORT_WAIT_TIMEOUT)
|
||||
assert proc.returncode is None, "process exited instead of execing"
|
||||
assert proc.pid == pid_before
|
||||
assert any("Encryption: offered" in line for line in lines)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user