aioamazondevices 3.1.17rc1__py3-none-any.whl → 3.1.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aioamazondevices/__init__.py +1 -1
- aioamazondevices/api.py +14 -12
- aioamazondevices/const.py +19 -0
- aioamazondevices/utils.py +58 -0
- {aioamazondevices-3.1.17rc1.dist-info → aioamazondevices-3.1.19.dist-info}/METADATA +2 -2
- aioamazondevices-3.1.19.dist-info/RECORD +11 -0
- aioamazondevices-3.1.17rc1.dist-info/RECORD +0 -10
- {aioamazondevices-3.1.17rc1.dist-info → aioamazondevices-3.1.19.dist-info}/LICENSE +0 -0
- {aioamazondevices-3.1.17rc1.dist-info → aioamazondevices-3.1.19.dist-info}/WHEEL +0 -0
aioamazondevices/__init__.py
CHANGED
aioamazondevices/api.py
CHANGED
@@ -58,6 +58,7 @@ from .exceptions import (
|
|
58
58
|
CannotRetrieveData,
|
59
59
|
WrongMethod,
|
60
60
|
)
|
61
|
+
from .utils import obfuscate_email, scrub_fields
|
61
62
|
|
62
63
|
|
63
64
|
@dataclass
|
@@ -317,7 +318,7 @@ class AmazonEchoApi:
|
|
317
318
|
"%s request: %s with payload %s [json=%s]",
|
318
319
|
method,
|
319
320
|
url,
|
320
|
-
input_data,
|
321
|
+
scrub_fields(input_data) if input_data else None,
|
321
322
|
json_data,
|
322
323
|
)
|
323
324
|
|
@@ -473,7 +474,7 @@ class AmazonEchoApi:
|
|
473
474
|
msg = resp_json["response"]["error"]["message"]
|
474
475
|
_LOGGER.error(
|
475
476
|
"Cannot register device for %s: %s",
|
476
|
-
self._login_email,
|
477
|
+
obfuscate_email(self._login_email),
|
477
478
|
msg,
|
478
479
|
)
|
479
480
|
raise CannotRegisterDevice(f"{HTTPStatus(resp.status).phrase}: {msg}")
|
@@ -601,7 +602,11 @@ class AmazonEchoApi:
|
|
601
602
|
|
602
603
|
async def login_mode_interactive(self, otp_code: str) -> dict[str, Any]:
|
603
604
|
"""Login to Amazon interactively via OTP."""
|
604
|
-
_LOGGER.debug(
|
605
|
+
_LOGGER.debug(
|
606
|
+
"Logging-in for %s [otp code: %s]",
|
607
|
+
obfuscate_email(self._login_email),
|
608
|
+
bool(otp_code),
|
609
|
+
)
|
605
610
|
self._client_session()
|
606
611
|
|
607
612
|
code_verifier = self._create_code_verifier()
|
@@ -671,7 +676,7 @@ class AmazonEchoApi:
|
|
671
676
|
|
672
677
|
_LOGGER.debug(
|
673
678
|
"Logging-in for %s with stored data",
|
674
|
-
self._login_email,
|
679
|
+
obfuscate_email(self._login_email),
|
675
680
|
)
|
676
681
|
|
677
682
|
self._client_session()
|
@@ -723,7 +728,11 @@ class AmazonEchoApi:
|
|
723
728
|
|
724
729
|
final_devices_list: dict[str, AmazonDevice] = {}
|
725
730
|
for device in self._devices.values():
|
726
|
-
|
731
|
+
# Remove stale, orphaned and virtual devices
|
732
|
+
devices_node = device.get(NODE_DEVICES)
|
733
|
+
if not devices_node or (devices_node.get("deviceType") in DEVICE_TO_IGNORE):
|
734
|
+
continue
|
735
|
+
|
727
736
|
preferences_node = device.get(NODE_PREFERENCES)
|
728
737
|
do_not_disturb_node = device[NODE_DO_NOT_DISTURB]
|
729
738
|
bluetooth_node = device[NODE_BLUETOOTH]
|
@@ -736,13 +745,6 @@ class AmazonEchoApi:
|
|
736
745
|
if _device_id == identifier_node["entityId"]:
|
737
746
|
sensors = _device_sensors
|
738
747
|
|
739
|
-
# Remove stale, orphaned and virtual devices
|
740
|
-
if (
|
741
|
-
NODE_DEVICES not in device
|
742
|
-
or devices_node.get("deviceType") in DEVICE_TO_IGNORE
|
743
|
-
):
|
744
|
-
continue
|
745
|
-
|
746
748
|
serial_number: str = devices_node["serialNumber"]
|
747
749
|
final_devices_list[serial_number] = AmazonDevice(
|
748
750
|
account_name=devices_node["accountName"],
|
aioamazondevices/const.py
CHANGED
@@ -6,6 +6,25 @@ _LOGGER = logging.getLogger(__package__)
|
|
6
6
|
|
7
7
|
DEFAULT_ASSOC_HANDLE = "amzn_dp_project_dee_ios"
|
8
8
|
|
9
|
+
TO_REDACT = {
|
10
|
+
"address1",
|
11
|
+
"address2",
|
12
|
+
"address3",
|
13
|
+
"city",
|
14
|
+
"county",
|
15
|
+
"deviceAccountId",
|
16
|
+
"deviceAddress",
|
17
|
+
"deviceOwnerCustomerId",
|
18
|
+
"given_name",
|
19
|
+
"name",
|
20
|
+
"password",
|
21
|
+
"postalCode",
|
22
|
+
"searchCustomerId",
|
23
|
+
"state",
|
24
|
+
"street",
|
25
|
+
"user_id",
|
26
|
+
}
|
27
|
+
|
9
28
|
DOMAIN_BY_ISO3166_COUNTRY = {
|
10
29
|
"ar": {
|
11
30
|
"domain": "com",
|
@@ -0,0 +1,58 @@
|
|
1
|
+
"""Utils module for Amazon devices."""
|
2
|
+
|
3
|
+
from collections.abc import Collection
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from .const import TO_REDACT
|
7
|
+
|
8
|
+
|
9
|
+
def obfuscate_email(email: str) -> str:
|
10
|
+
"""Obfuscate an email address partially."""
|
11
|
+
try:
|
12
|
+
username, domain = email.split("@")
|
13
|
+
domain_name, domain_ext = domain.rsplit(".", 1)
|
14
|
+
|
15
|
+
def obfuscate_part(part: str, visible: int = 1) -> str:
|
16
|
+
if len(part) <= visible:
|
17
|
+
return "*" * len(part)
|
18
|
+
return part[:visible] + "*" * (len(part) - visible)
|
19
|
+
|
20
|
+
# Obfuscate username and domain parts
|
21
|
+
obf_user = ".".join(obfuscate_part(u, 1) for u in username.split("."))
|
22
|
+
obf_domain = obfuscate_part(domain_name, 1)
|
23
|
+
|
24
|
+
except (SyntaxError, ValueError):
|
25
|
+
return "[invalid email]"
|
26
|
+
else:
|
27
|
+
return f"{obf_user}@{obf_domain}.{domain_ext}"
|
28
|
+
|
29
|
+
|
30
|
+
def scrub_fields(
|
31
|
+
obj: Any, # noqa: ANN401
|
32
|
+
field_names: Collection[str] = TO_REDACT,
|
33
|
+
replacement: str = "[REDACTED]",
|
34
|
+
) -> Any: # noqa: ANN401
|
35
|
+
"""Return a deep-copied version of *obj* with redacted keys."""
|
36
|
+
if isinstance(obj, dict):
|
37
|
+
result = {}
|
38
|
+
for k, v in obj.items():
|
39
|
+
# If the key itself is sensitive → overwrite its value
|
40
|
+
if k in field_names:
|
41
|
+
result[k] = replacement
|
42
|
+
else:
|
43
|
+
# Otherwise keep walking
|
44
|
+
result[k] = scrub_fields(v, field_names, replacement)
|
45
|
+
return result
|
46
|
+
|
47
|
+
if isinstance(obj, list):
|
48
|
+
return [scrub_fields(item, field_names, replacement) for item in obj]
|
49
|
+
|
50
|
+
if isinstance(obj, tuple):
|
51
|
+
return tuple(scrub_fields(item, field_names, replacement) for item in obj)
|
52
|
+
|
53
|
+
if isinstance(obj, set):
|
54
|
+
# Note: a set cannot contain mutable/unhashable items like dicts,
|
55
|
+
# so we assume its members are hashable after scrubbing.
|
56
|
+
return {scrub_fields(item, field_names, replacement) for item in obj}
|
57
|
+
|
58
|
+
return obj
|
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: aioamazondevices
|
3
|
-
Version: 3.1.
|
3
|
+
Version: 3.1.19
|
4
4
|
Summary: Python library to control Amazon devices
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: Simone Chemelli
|
7
7
|
Author-email: simone.chemelli@gmail.com
|
8
8
|
Requires-Python: >=3.12
|
9
|
-
Classifier: Development Status ::
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
10
10
|
Classifier: Intended Audience :: Developers
|
11
11
|
Classifier: Natural Language :: English
|
12
12
|
Classifier: Operating System :: OS Independent
|
@@ -0,0 +1,11 @@
|
|
1
|
+
aioamazondevices/__init__.py,sha256=yYJH7153YmQfYcpIzSJNgHgxNQI7bZK5Aq0emVmfVQg,277
|
2
|
+
aioamazondevices/api.py,sha256=7IJF_bOSs0C1fLKeOR2Y87qyADlfGEGWlihZ2vlLaL8,36250
|
3
|
+
aioamazondevices/const.py,sha256=KQbHCOvzBTcWMc3O-kLR72wJJDBbrFK9dPHJVEPMY4M,8528
|
4
|
+
aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
|
5
|
+
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
|
7
|
+
aioamazondevices/utils.py,sha256=1PrzAtQHigN2rGxdMVPKzbjOnwh-MLc9YWkQaVQIHT4,1941
|
8
|
+
aioamazondevices-3.1.19.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
9
|
+
aioamazondevices-3.1.19.dist-info/METADATA,sha256=eOPZwC2lraH2xYJgydkqHCnPoe96hYBy0Qmua9AltY8,5235
|
10
|
+
aioamazondevices-3.1.19.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
11
|
+
aioamazondevices-3.1.19.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
aioamazondevices/__init__.py,sha256=-DEB2sLPnC-46esN6l_NTZB1KlUE4XuMdEVWFW5-y1o,277
|
2
|
-
aioamazondevices/api.py,sha256=sLfD1-K2H32zgR03UvcBP-xBdwrF1b0VHs0ttfar7nY,36110
|
3
|
-
aioamazondevices/const.py,sha256=sNtoAN22sawIKES6TghRA_kvfe061Oliw_VvYJNklNA,8234
|
4
|
-
aioamazondevices/exceptions.py,sha256=JDnSFi_7oEhqK31sHXf0S_cyMoMjiRJuLp4ow7mYgLY,643
|
5
|
-
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
aioamazondevices/sounds.py,sha256=01pVCDFIuhrLypXInw4JNuHsC6zjMLsuKocet1R6we8,13409
|
7
|
-
aioamazondevices-3.1.17rc1.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
8
|
-
aioamazondevices-3.1.17rc1.dist-info/METADATA,sha256=-7MfUws8OCh7TwQwyd_HEU684aMqV697LRC_6ReCPRE,5243
|
9
|
-
aioamazondevices-3.1.17rc1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
10
|
-
aioamazondevices-3.1.17rc1.dist-info/RECORD,,
|
File without changes
|
File without changes
|