Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"