Skip to content

AES Transport creates the key even if the device is offline #675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bdraco opened this issue Jan 23, 2024 · 1 comment · Fixed by #687
Closed

AES Transport creates the key even if the device is offline #675

bdraco opened this issue Jan 23, 2024 · 1 comment · Fixed by #687
Milestone

Comments

@bdraco
Copy link
Member

bdraco commented Jan 23, 2024

Screenshot 2024-01-22 at 7 00 21 PM

suggested solution is https://docs.aiohttp.org/en/stable/client_quickstart.html#streaming-uploads

diff --git a/kasa/aestransport.py b/kasa/aestransport.py
index 65b0045..ca74cc6 100644
--- a/kasa/aestransport.py
+++ b/kasa/aestransport.py
@@ -8,7 +8,7 @@ import base64
 import hashlib
 import logging
 import time
-from typing import Dict, Optional, cast
+from typing import Dict, Optional, cast, TYPE_CHECKING
 
 from cryptography.hazmat.primitives import padding, serialization
 from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding
@@ -86,6 +86,8 @@ class AesTransport(BaseTransport):
 
         self._login_token = None
 
+        self._key_pair: Optional[KeyPair] = None
+
         _LOGGER.debug("Created AES transport for %s", self._host)
 
     @property
@@ -185,33 +187,35 @@ class AesTransport(BaseTransport):
         self._handle_response_error_code(resp_dict, "Error logging in")
         self._login_token = resp_dict["result"]["token"]
 
+    async def _generate_request_body(self) -> str:
+        """Generate the request body."""
+        self._key_pair = KeyPair.create_key_pair()
+        pub_key = (
+            "-----BEGIN PUBLIC KEY-----\n"
+            + self._key_pair.get_public_key()
+            + "\n-----END PUBLIC KEY-----\n"
+        )
+        handshake_params = {"key": pub_key}
+        _LOGGER.debug(f"Handshake params: {handshake_params}")
+        request_body = {"method": "handshake", "params": handshake_params}
+        _LOGGER.debug(f"Request {request_body}")
+        return json_dumps(request_body)
+
     async def perform_handshake(self):
         """Perform the handshake."""
         _LOGGER.debug("Will perform handshaking...")
         _LOGGER.debug("Generating keypair")
 
+        self._key_pair = None
         self._handshake_done = False
         self._session_expire_at = None
         self._session_cookie = None
 
         url = f"http://{self._host}/app"
-        key_pair = KeyPair.create_key_pair()
-
-        pub_key = (
-            "-----BEGIN PUBLIC KEY-----\n"
-            + key_pair.get_public_key()
-            + "\n-----END PUBLIC KEY-----\n"
-        )
-        handshake_params = {"key": pub_key}
-        _LOGGER.debug(f"Handshake params: {handshake_params}")
-
-        request_body = {"method": "handshake", "params": handshake_params}
-
-        _LOGGER.debug(f"Request {request_body}")
 
         status_code, resp_dict = await self._http_client.post(
             url,
-            json=request_body,
+            data=self._generate_request_body(),
             headers=self.COMMON_HEADERS,
             cookies_dict=self._session_cookie,
         )
@@ -240,8 +244,10 @@ class AesTransport(BaseTransport):
             self._session_cookie = {self.SESSION_COOKIE_NAME: cookie}
 
         self._session_expire_at = time.time() + 86400
+        if TYPE_CHECKING:
+            assert self._key_pair is not None
         self._encryption_session = AesEncyptionSession.create_from_keypair(
-            handshake_key, key_pair
+            handshake_key, self._key_pair
         )
 
         self._handshake_done = True
@rytilahti rytilahti added this to the 0.6.0.2 milestone Jan 23, 2024
@sdb9696
Copy link
Collaborator

sdb9696 commented Jan 23, 2024

PR created #687.

aiohttp needs an async_generator rather than a coroutine but this works.

rytilahti added a commit to rytilahti/python-kasa that referenced this issue Jan 25, 2024
[Full Changelog](python-kasa/python-kasa@0.6.0.1...0.6.1)

Release highlights:
* Support for tapo wall switches
* Support for unprovisioned devices
* Performance and stability improvements

**Implemented enhancements:**

- Add support for tapo wall switches \(S500D\) [\python-kasa#704](python-kasa#704) (@bdraco)
- Add new cli command 'command' to execute arbitrary commands [\python-kasa#692](python-kasa#692) (@rytilahti)
- Allow raw-command and wifi without update [\python-kasa#688](python-kasa#688) (@rytilahti)
- Generate AES KeyPair lazily [\python-kasa#687](python-kasa#687) (@sdb9696)
- Add reboot and factory\_reset to tapodevice [\python-kasa#686](python-kasa#686) (@rytilahti)
- Try default tapo credentials for klap and aes [\python-kasa#685](python-kasa#685) (@sdb9696)
- Sleep between discovery packets [\python-kasa#656](python-kasa#656) (@sdb9696)

**Fixed bugs:**

- Do not crash on missing geolocation [\python-kasa#701](python-kasa#701) (@rytilahti)
- Fix P100 error getting conn closed when trying default login after login failure [\python-kasa#690](python-kasa#690) (@sdb9696)

**Documentation updates:**

- Add protocol and transport documentation [\python-kasa#663](python-kasa#663) (@sdb9696)
- Document authenticated provisioning [\python-kasa#634](python-kasa#634) (@rytilahti)

**Closed issues:**

- Consider handshake as still valid on ServerDisconnectedError [\python-kasa#676](python-kasa#676)
- AES Transport creates the key even if the device is offline [\python-kasa#675](python-kasa#675)
- how to provision new Tapo plug devices? [\python-kasa#565](python-kasa#565)
- Space out discovery requests [\python-kasa#229](python-kasa#229)

**Merged pull requests:**

- Add additional L900-10 fixture [\python-kasa#707](python-kasa#707) (@bdraco)
- Replace rich formatting stripper [\python-kasa#706](python-kasa#706) (@bdraco)
- Add support for the S500 [\python-kasa#705](python-kasa#705) (@bdraco)
- Fix overly greedy \_strip\_rich\_formatting [\python-kasa#703](python-kasa#703) (@bdraco)
- Ensure login token is only sent if aes state is ESTABLISHED [\python-kasa#702](python-kasa#702) (@bdraco)
- Update readme fixture checker and readme [\python-kasa#699](python-kasa#699) (@rytilahti)
- Fix test\_klapprotocol test duration [\python-kasa#698](python-kasa#698) (@sdb9696)
- Renew the handshake session 20 minutes before we think it will expire [\python-kasa#697](python-kasa#697) (@bdraco)
- Add --batch-size hint to timeout errors in dump\_devinfo [\python-kasa#696](python-kasa#696) (@sdb9696)
- Add L930-5 fixture [\python-kasa#694](python-kasa#694) (@bdraco)
- Add fixtures for L510E [\python-kasa#693](python-kasa#693) (@bdraco)
- Refactor aestransport to use a state enum [\python-kasa#691](python-kasa#691) (@bdraco)
- Update transport close/reset behaviour [\python-kasa#689](python-kasa#689) (@sdb9696)
- Check README for supported models [\python-kasa#684](python-kasa#684) (@rytilahti)
- Add P100 test fixture [\python-kasa#683](python-kasa#683) (@bdraco)
- Make dump\_devinfo request batch size configurable [\python-kasa#681](python-kasa#681) (@sdb9696)
- Add updated L920 fixture [\python-kasa#680](python-kasa#680) (@bdraco)
- Update fixtures from test devices [\python-kasa#679](python-kasa#679) (@bdraco)
- Show discovery data for state with verbose [\python-kasa#678](python-kasa#678) (@rytilahti)
- Add L530E\(US\) fixture [\python-kasa#674](python-kasa#674) (@bdraco)
- Add P135 fixture [\python-kasa#673](python-kasa#673) (@bdraco)
- Rename base TPLinkProtocol to BaseProtocol [\python-kasa#669](python-kasa#669) (@sdb9696)
- Add 1003 \(TRANSPORT\_UNKNOWN\_CREDENTIALS\_ERROR\) [\python-kasa#667](python-kasa#667) (@rytilahti)
rytilahti added a commit that referenced this issue Jan 25, 2024
[Full Changelog](0.6.0.1...0.6.1)

Release highlights:
* Support for tapo wall switches
* Support for unprovisioned devices
* Performance and stability improvements

**Implemented enhancements:**

- Add support for tapo wall switches \(S500D\) [\#704](#704) (@bdraco)
- Add new cli command 'command' to execute arbitrary commands [\#692](#692) (@rytilahti)
- Allow raw-command and wifi without update [\#688](#688) (@rytilahti)
- Generate AES KeyPair lazily [\#687](#687) (@sdb9696)
- Add reboot and factory\_reset to tapodevice [\#686](#686) (@rytilahti)
- Try default tapo credentials for klap and aes [\#685](#685) (@sdb9696)
- Sleep between discovery packets [\#656](#656) (@sdb9696)

**Fixed bugs:**

- Do not crash on missing geolocation [\#701](#701) (@rytilahti)
- Fix P100 error getting conn closed when trying default login after login failure [\#690](#690) (@sdb9696)

**Documentation updates:**

- Add protocol and transport documentation [\#663](#663) (@sdb9696)
- Document authenticated provisioning [\#634](#634) (@rytilahti)

**Closed issues:**

- Consider handshake as still valid on ServerDisconnectedError [\#676](#676)
- AES Transport creates the key even if the device is offline [\#675](#675)
- how to provision new Tapo plug devices? [\#565](#565)
- Space out discovery requests [\#229](#229)

**Merged pull requests:**

- Add additional L900-10 fixture [\#707](#707) (@bdraco)
- Replace rich formatting stripper [\#706](#706) (@bdraco)
- Add support for the S500 [\#705](#705) (@bdraco)
- Fix overly greedy \_strip\_rich\_formatting [\#703](#703) (@bdraco)
- Ensure login token is only sent if aes state is ESTABLISHED [\#702](#702) (@bdraco)
- Update readme fixture checker and readme [\#699](#699) (@rytilahti)
- Fix test\_klapprotocol test duration [\#698](#698) (@sdb9696)
- Renew the handshake session 20 minutes before we think it will expire [\#697](#697) (@bdraco)
- Add --batch-size hint to timeout errors in dump\_devinfo [\#696](#696) (@sdb9696)
- Add L930-5 fixture [\#694](#694) (@bdraco)
- Add fixtures for L510E [\#693](#693) (@bdraco)
- Refactor aestransport to use a state enum [\#691](#691) (@bdraco)
- Update transport close/reset behaviour [\#689](#689) (@sdb9696)
- Check README for supported models [\#684](#684) (@rytilahti)
- Add P100 test fixture [\#683](#683) (@bdraco)
- Make dump\_devinfo request batch size configurable [\#681](#681) (@sdb9696)
- Add updated L920 fixture [\#680](#680) (@bdraco)
- Update fixtures from test devices [\#679](#679) (@bdraco)
- Show discovery data for state with verbose [\#678](#678) (@rytilahti)
- Add L530E\(US\) fixture [\#674](#674) (@bdraco)
- Add P135 fixture [\#673](#673) (@bdraco)
- Rename base TPLinkProtocol to BaseProtocol [\#669](#669) (@sdb9696)
- Add 1003 \(TRANSPORT\_UNKNOWN\_CREDENTIALS\_ERROR\) [\#667](#667) (@rytilahti)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants