mirror of
https://github.com/python-kasa/python-kasa.git
synced 2026-02-25 20:30:05 +00:00
Add support for tapo login_version 3 in sslaestransport (#1638)
Updates to get_default_credentials and DEFAULT_CREDENTIALS for handling a new default password for encryption_type 3 in TAPOCAMERA devices that use encryption_type 3. This adds support for devices like TC40.
This commit is contained in:
@@ -201,7 +201,7 @@ The following devices have been tested and confirmed as working. If your device
|
||||
- **Wall Switches**: S210, S220, S500, S500D, S505, S505D, TS15
|
||||
- **Bulbs**: L430C, L430P, L510B, L510E, L530B, L530E, L535E, L630
|
||||
- **Light Strips**: L900-10, L900-5, L920-5, L930-5
|
||||
- **Cameras**: C100, C110, C210, C220, C225, C325WB, C460, C520WS, C720, TC65, TC70
|
||||
- **Cameras**: C100, C110, C210, C220, C225, C325WB, C460, C520WS, C720, TC40, TC65, TC70
|
||||
- **Doorbells and chimes**: D100C, D130, D230
|
||||
- **Vacuums**: RV20 Max Plus, RV30 Max
|
||||
- **Hubs**: H100, H200
|
||||
|
||||
@@ -320,6 +320,8 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
|
||||
- Hardware: 1.0 (US) / Firmware: 1.2.8
|
||||
- **C720**
|
||||
- Hardware: 1.0 (US) / Firmware: 1.2.3
|
||||
- **TC40**
|
||||
- Hardware: 2.0 (EU) / Firmware: 1.0.4
|
||||
- **TC65**
|
||||
- Hardware: 1.0 / Firmware: 1.3.9
|
||||
- **TC70**
|
||||
|
||||
@@ -16,10 +16,10 @@ class Credentials:
|
||||
password: str = field(default="", repr=False)
|
||||
|
||||
|
||||
def get_default_credentials(tuple: tuple[str, str]) -> Credentials:
|
||||
def get_default_credentials(crdentials: tuple[str, str]) -> Credentials:
|
||||
"""Return decoded default credentials."""
|
||||
un = base64.b64decode(tuple[0].encode()).decode()
|
||||
pw = base64.b64decode(tuple[1].encode()).decode()
|
||||
un = base64.b64decode(crdentials[0].encode()).decode()
|
||||
pw = base64.b64decode(crdentials[1].encode()).decode()
|
||||
return Credentials(un, pw)
|
||||
|
||||
|
||||
@@ -28,4 +28,5 @@ DEFAULT_CREDENTIALS = {
|
||||
"KASACAMERA": ("YWRtaW4=", "MjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzM="),
|
||||
"TAPO": ("dGVzdEB0cC1saW5rLm5ldA==", "dGVzdA=="),
|
||||
"TAPOCAMERA": ("YWRtaW4=", "YWRtaW4="),
|
||||
"TAPOCAMERA_LV3": ("YWRtaW4=", "VFBMMDc1NTI2NDYwNjAz"),
|
||||
}
|
||||
|
||||
@@ -95,8 +95,12 @@ class SslAesTransport(BaseTransport):
|
||||
not self._credentials or self._credentials.username is None
|
||||
) and not self._credentials_hash:
|
||||
self._credentials = Credentials()
|
||||
if self._login_version == 3:
|
||||
_default_credentials = DEFAULT_CREDENTIALS["TAPOCAMERA_LV3"]
|
||||
else:
|
||||
_default_credentials = DEFAULT_CREDENTIALS["TAPOCAMERA"]
|
||||
self._default_credentials: Credentials = get_default_credentials(
|
||||
DEFAULT_CREDENTIALS["TAPOCAMERA"]
|
||||
_default_credentials
|
||||
)
|
||||
self._http_client: HttpClient = HttpClient(config)
|
||||
|
||||
|
||||
1037
tests/fixtures/smartcam/TC40(EU)_2.0_1.0.4.json
vendored
Normal file
1037
tests/fixtures/smartcam/TC40(EU)_2.0_1.0.4.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import secrets
|
||||
from contextlib import nullcontext as does_not_raise
|
||||
@@ -12,7 +13,12 @@ import pytest
|
||||
from yarl import URL
|
||||
|
||||
from kasa.credentials import DEFAULT_CREDENTIALS, Credentials, get_default_credentials
|
||||
from kasa.deviceconfig import DeviceConfig
|
||||
from kasa.deviceconfig import (
|
||||
DeviceConfig,
|
||||
DeviceConnectionParameters,
|
||||
DeviceEncryptionType,
|
||||
DeviceFamily,
|
||||
)
|
||||
from kasa.exceptions import (
|
||||
AuthenticationError,
|
||||
DeviceError,
|
||||
@@ -393,6 +399,53 @@ async def test_port_override():
|
||||
assert str(transport._app_url) == f"https://127.0.0.1:{port_override}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("login_version", "expected_password_b64"),
|
||||
[
|
||||
pytest.param(
|
||||
3,
|
||||
"VFBMMDc1NTI2NDYwNjAz", # noqa: S105
|
||||
id="version-3-uses-lv3-credentials",
|
||||
),
|
||||
pytest.param(
|
||||
2,
|
||||
"YWRtaW4=", # noqa: S105
|
||||
id="version-2-uses-tapocamera-credentials",
|
||||
),
|
||||
pytest.param(
|
||||
None,
|
||||
"YWRtaW4=", # noqa: S105
|
||||
id="no-version-uses-tapocamera-credentials",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_login_version_default_credentials(
|
||||
mocker, login_version, expected_password_b64
|
||||
):
|
||||
"""Test that login_version=3 uses TAPOCAMERA_LV3 credentials while other versions use TAPOCAMERA."""
|
||||
host = "127.0.0.1"
|
||||
tapo_family = DeviceFamily.SmartIpCamera
|
||||
aes_type = DeviceEncryptionType.Aes
|
||||
mock_ssl_aes_device = MockSslAesDevice(host)
|
||||
mocker.patch.object(
|
||||
aiohttp.ClientSession, "post", side_effect=mock_ssl_aes_device.post
|
||||
)
|
||||
|
||||
config = DeviceConfig(
|
||||
host,
|
||||
credentials=Credentials("foo", "bar"),
|
||||
connection_type=DeviceConnectionParameters(
|
||||
tapo_family, aes_type, login_version=login_version
|
||||
),
|
||||
)
|
||||
transport = SslAesTransport(config=config)
|
||||
assert transport._default_credentials.username == "admin"
|
||||
password_b64 = base64.b64encode(
|
||||
transport._default_credentials.password.encode()
|
||||
).decode()
|
||||
assert password_b64 == expected_password_b64
|
||||
|
||||
|
||||
class MockSslAesDevice:
|
||||
BAD_USER_RESP = {
|
||||
"error_code": SmartErrorCode.SESSION_EXPIRED.value,
|
||||
|
||||
Reference in New Issue
Block a user