Skip to content

Commit

Permalink
Fix port-override for aes&klap transports (#734)
Browse files Browse the repository at this point in the history
* Fix port-override for aes&klap transports

* Add tests for port override
  • Loading branch information
rytilahti committed Feb 3, 2024
1 parent 414489f commit fae071f
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 13 deletions.
5 changes: 2 additions & 3 deletions kasa/aestransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def __init__(
self._session_cookie: Optional[Dict[str, str]] = None

self._key_pair: Optional[KeyPair] = None
self._app_url = URL(f"http://{self._host}/app")
self._app_url = URL(f"http://{self._host}:{self._port}/app")
self._token_url: Optional[URL] = None

_LOGGER.debug("Created AES transport for %s", self._host)
Expand Down Expand Up @@ -257,7 +257,6 @@ async def perform_handshake(self) -> None:
self._session_expire_at = None
self._session_cookie = None

url = f"http://{self._host}/app"
# Device needs the content length or it will response with 500
headers = {
**self.COMMON_HEADERS,
Expand All @@ -266,7 +265,7 @@ async def perform_handshake(self) -> None:
http_client = self._http_client

status_code, resp_dict = await http_client.post(
url,
self._app_url,
json=self._generate_key_pair_payload(),
headers=headers,
cookies_dict=self._session_cookie,
Expand Down
1 change: 1 addition & 0 deletions kasa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ def _nop_echo(*args, **kwargs):
)
config = DeviceConfig(
host=host,
port_override=port,
credentials=credentials,
credentials_hash=credentials_hash,
timeout=timeout,
Expand Down
4 changes: 4 additions & 0 deletions kasa/httpclient.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Module for HttpClientSession class."""
import asyncio
import logging
from typing import Any, Dict, Optional, Tuple, Union

import aiohttp
Expand All @@ -13,6 +14,8 @@
)
from .json import loads as json_loads

_LOGGER = logging.getLogger(__name__)


def get_cookie_jar() -> aiohttp.CookieJar:
"""Return a new cookie jar with the correct options for device communication."""
Expand Down Expand Up @@ -54,6 +57,7 @@ async def post(
If the request is provided via the json parameter json will be returned.
"""
_LOGGER.debug("Posting to %s", url)
response_data = None
self._last_url = url
self.client.cookie_jar.clear()
Expand Down
2 changes: 1 addition & 1 deletion kasa/klaptransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def __init__(
self._session_cookie: Optional[Dict[str, Any]] = None

_LOGGER.debug("Created KLAP transport for %s", self._host)
self._app_url = URL(f"http://{self._host}/app")
self._app_url = URL(f"http://{self._host}:{self._port}/app")
self._request_url = self._app_url / "request"

@property
Expand Down
13 changes: 12 additions & 1 deletion kasa/tests/test_aestransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,17 @@ async def test_passthrough_errors(mocker, error_code):
await transport.send(json_dumps(request))


async def test_port_override():
"""Test that port override sets the app_url."""
host = "127.0.0.1"
config = DeviceConfig(
host, credentials=Credentials("foo", "bar"), port_override=12345
)
transport = AesTransport(config=config)

assert str(transport._app_url) == "http://127.0.0.1:12345/app"


class MockAesDevice:
class _mock_response:
def __init__(self, status, json: dict):
Expand Down Expand Up @@ -256,7 +267,7 @@ async def _post(self, url: URL, json: Dict[str, Any]):
elif json["method"] == "login_device":
return await self._return_login_response(url, json)
else:
assert str(url) == f"http://{self.host}/app?token={self.token}"
assert str(url) == f"http://{self.host}:80/app?token={self.token}"
return await self._return_send_response(url, json)

async def _return_handshake_response(self, url: URL, json: Dict[str, Any]):
Expand Down
27 changes: 19 additions & 8 deletions kasa/tests/test_klapprotocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,14 @@ async def test_handshake(
async def _return_handshake_response(url: URL, params=None, data=None, *_, **__):
nonlocal client_seed, server_seed, device_auth_hash

if str(url) == "http://127.0.0.1/app/handshake1":
if str(url) == "http://127.0.0.1:80/app/handshake1":
client_seed = data
seed_auth_hash = _sha256(
seed_auth_hash_calc1(client_seed, server_seed, device_auth_hash)
)

return _mock_response(200, server_seed + seed_auth_hash)
elif str(url) == "http://127.0.0.1/app/handshake2":
elif str(url) == "http://127.0.0.1:80/app/handshake2":
seed_auth_hash = _sha256(
seed_auth_hash_calc2(client_seed, server_seed, device_auth_hash)
)
Expand Down Expand Up @@ -367,14 +367,14 @@ async def test_query(mocker):
async def _return_response(url: URL, params=None, data=None, *_, **__):
nonlocal client_seed, server_seed, device_auth_hash, seq

if str(url) == "http://127.0.0.1/app/handshake1":
if str(url) == "http://127.0.0.1:80/app/handshake1":
client_seed = data
client_seed_auth_hash = _sha256(data + device_auth_hash)

return _mock_response(200, server_seed + client_seed_auth_hash)
elif str(url) == "http://127.0.0.1/app/handshake2":
elif str(url) == "http://127.0.0.1:80/app/handshake2":
return _mock_response(200, b"")
elif str(url) == "http://127.0.0.1/app/request":
elif str(url) == "http://127.0.0.1:80/app/request":
encryption_session = KlapEncryptionSession(
protocol._transport._encryption_session.local_seed,
protocol._transport._encryption_session.remote_seed,
Expand Down Expand Up @@ -419,16 +419,16 @@ async def test_authentication_failures(mocker, response_status, expectation):
async def _return_response(url: URL, params=None, data=None, *_, **__):
nonlocal client_seed, server_seed, device_auth_hash, response_status

if str(url) == "http://127.0.0.1/app/handshake1":
if str(url) == "http://127.0.0.1:80/app/handshake1":
client_seed = data
client_seed_auth_hash = _sha256(data + device_auth_hash)

return _mock_response(
response_status[0], server_seed + client_seed_auth_hash
)
elif str(url) == "http://127.0.0.1/app/handshake2":
elif str(url) == "http://127.0.0.1:80/app/handshake2":
return _mock_response(response_status[1], b"")
elif str(url) == "http://127.0.0.1/app/request":
elif str(url) == "http://127.0.0.1:80/app/request":
return _mock_response(response_status[2], b"")

mocker.patch.object(aiohttp.ClientSession, "post", side_effect=_return_response)
Expand All @@ -438,3 +438,14 @@ async def _return_response(url: URL, params=None, data=None, *_, **__):

with expectation:
await protocol.query({})


async def test_port_override():
"""Test that port override sets the app_url."""
host = "127.0.0.1"
config = DeviceConfig(
host, credentials=Credentials("foo", "bar"), port_override=12345
)
transport = KlapTransport(config=config)

assert str(transport._app_url) == "http://127.0.0.1:12345/app"

0 comments on commit fae071f

Please sign in to comment.