aioamazondevices 0.1.0__py3-none-any.whl → 0.2.0__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 +55 -30
- {aioamazondevices-0.1.0.dist-info → aioamazondevices-0.2.0.dist-info}/METADATA +1 -1
- aioamazondevices-0.2.0.dist-info/RECORD +9 -0
- aioamazondevices-0.1.0.dist-info/RECORD +0 -9
- {aioamazondevices-0.1.0.dist-info → aioamazondevices-0.2.0.dist-info}/LICENSE +0 -0
- {aioamazondevices-0.1.0.dist-info → aioamazondevices-0.2.0.dist-info}/WHEEL +0 -0
aioamazondevices/__init__.py
CHANGED
aioamazondevices/api.py
CHANGED
@@ -5,6 +5,7 @@ import hashlib
|
|
5
5
|
import secrets
|
6
6
|
import uuid
|
7
7
|
from dataclasses import dataclass
|
8
|
+
from pathlib import Path
|
8
9
|
from typing import Any
|
9
10
|
from urllib.parse import urlencode
|
10
11
|
|
@@ -39,27 +40,6 @@ class AmazonDevice:
|
|
39
40
|
wifi: str
|
40
41
|
|
41
42
|
|
42
|
-
def _build_init_cookies() -> dict[str, str]:
|
43
|
-
"""Build initial cookies to prevent captcha in most cases."""
|
44
|
-
token_bytes = secrets.token_bytes(313)
|
45
|
-
frc = base64.b64encode(token_bytes).decode("ascii").rstrip("=")
|
46
|
-
|
47
|
-
map_md_dict = {
|
48
|
-
"device_user_dictionary": [],
|
49
|
-
"device_registration_data": {
|
50
|
-
"software_version": AMAZON_SOFTWARE_VERSION,
|
51
|
-
},
|
52
|
-
"app_identifier": {
|
53
|
-
"app_version": AMAZON_APP_VERSION,
|
54
|
-
"bundle_id": AMAZON_APP_BUNDLE_ID,
|
55
|
-
},
|
56
|
-
}
|
57
|
-
map_md_str = orjson.dumps(map_md_dict).decode("utf-8")
|
58
|
-
map_md = base64.b64encode(map_md_str.encode()).decode().rstrip("=")
|
59
|
-
|
60
|
-
return {"frc": frc, "map-md": map_md, "amzn-app-id": AMAZON_APP_ID}
|
61
|
-
|
62
|
-
|
63
43
|
class AmazonEchoApi:
|
64
44
|
"""Queries Amazon for Echo devices."""
|
65
45
|
|
@@ -68,25 +48,50 @@ class AmazonEchoApi:
|
|
68
48
|
login_country_code: str,
|
69
49
|
login_email: str,
|
70
50
|
login_password: str,
|
51
|
+
save_html: bool = False,
|
71
52
|
) -> None:
|
72
53
|
"""Initialize the scanner."""
|
73
|
-
|
74
|
-
|
54
|
+
# Force country digits as lower case
|
55
|
+
country_code = login_country_code.lower()
|
56
|
+
|
57
|
+
locale = DOMAIN_BY_COUNTRY.get(country_code)
|
58
|
+
domain = locale["domain"] if locale else country_code
|
75
59
|
|
76
60
|
assoc_handle = "amzn_dp_project_dee_ios"
|
77
61
|
if not locale:
|
78
|
-
assoc_handle += f"_{
|
62
|
+
assoc_handle += f"_{country_code}"
|
79
63
|
self._assoc_handle = assoc_handle
|
80
64
|
|
81
65
|
self._login_email = login_email
|
82
66
|
self._login_password = login_password
|
83
67
|
self._domain = domain
|
84
68
|
self._url = f"https://www.amazon.{domain}"
|
85
|
-
self._cookies = _build_init_cookies()
|
69
|
+
self._cookies = self._build_init_cookies()
|
86
70
|
self._headers = DEFAULT_HEADERS
|
71
|
+
self._save_html = save_html
|
87
72
|
|
88
73
|
self.session: AsyncClient
|
89
74
|
|
75
|
+
def _build_init_cookies(self) -> dict[str, str]:
|
76
|
+
"""Build initial cookies to prevent captcha in most cases."""
|
77
|
+
token_bytes = secrets.token_bytes(313)
|
78
|
+
frc = base64.b64encode(token_bytes).decode("ascii").rstrip("=")
|
79
|
+
|
80
|
+
map_md_dict = {
|
81
|
+
"device_user_dictionary": [],
|
82
|
+
"device_registration_data": {
|
83
|
+
"software_version": AMAZON_SOFTWARE_VERSION,
|
84
|
+
},
|
85
|
+
"app_identifier": {
|
86
|
+
"app_version": AMAZON_APP_VERSION,
|
87
|
+
"bundle_id": AMAZON_APP_BUNDLE_ID,
|
88
|
+
},
|
89
|
+
}
|
90
|
+
map_md_str = orjson.dumps(map_md_dict).decode("utf-8")
|
91
|
+
map_md = base64.b64encode(map_md_str.encode()).decode().rstrip("=")
|
92
|
+
|
93
|
+
return {"frc": frc, "map-md": map_md, "amzn-app-id": AMAZON_APP_ID}
|
94
|
+
|
90
95
|
def _create_code_verifier(self, length: int = 32) -> bytes:
|
91
96
|
"""Create code verifier."""
|
92
97
|
verifier = secrets.token_bytes(length)
|
@@ -97,18 +102,18 @@ class AmazonEchoApi:
|
|
97
102
|
m = hashlib.sha256(verifier)
|
98
103
|
return base64.urlsafe_b64encode(m.digest()).rstrip(b"=")
|
99
104
|
|
100
|
-
def _build_client_id(self) -> str:
|
105
|
+
def _build_client_id(self, serial: str) -> str:
|
101
106
|
"""Build client ID."""
|
102
|
-
serial = uuid.uuid4().hex.upper()
|
103
107
|
client_id = serial.encode() + AMAZON_SERIAL_NUMBER
|
104
108
|
return client_id.hex()
|
105
109
|
|
106
110
|
def _build_oauth_url(
|
107
111
|
self,
|
112
|
+
code_verifier: bytes,
|
113
|
+
client_id: str,
|
108
114
|
) -> str:
|
109
115
|
"""Build the url to login to Amazon as a Mobile device."""
|
110
|
-
|
111
|
-
code_challenge = self._create_s256_code_challenge(self._create_code_verifier())
|
116
|
+
code_challenge = self._create_s256_code_challenge(code_verifier)
|
112
117
|
|
113
118
|
oauth_params = {
|
114
119
|
"openid.oa2.response_type": "code",
|
@@ -180,15 +185,34 @@ class AmazonEchoApi:
|
|
180
185
|
url,
|
181
186
|
data=input_data,
|
182
187
|
)
|
188
|
+
|
189
|
+
await self._save_to_file(
|
190
|
+
resp.text,
|
191
|
+
url,
|
192
|
+
)
|
183
193
|
return BeautifulSoup(resp.content, "html.parser"), resp
|
184
194
|
|
195
|
+
async def _save_to_file(self, html_code: str, url: str) -> None:
|
196
|
+
"""Sage HTML data to disk."""
|
197
|
+
if not self._save_html:
|
198
|
+
return
|
199
|
+
|
200
|
+
url_split = url.split("/")
|
201
|
+
filename = f"{url_split[3]}-{url_split[4].split('?')[0]}.html"
|
202
|
+
with Path.open(Path(filename), "w+") as file:
|
203
|
+
file.write(html_code)
|
204
|
+
file.write("\n")
|
205
|
+
|
185
206
|
async def login(self, otp_code: str) -> bool:
|
186
207
|
"""Login to Amazon."""
|
187
208
|
_LOGGER.debug("Logging-in for %s [otp code %s]", self._login_email, otp_code)
|
188
209
|
self._client_session()
|
189
210
|
|
211
|
+
code_verifier = self._create_code_verifier()
|
212
|
+
client_id = self._build_client_id(uuid.uuid4().hex.upper())
|
213
|
+
|
190
214
|
_LOGGER.debug("Build oauth URL")
|
191
|
-
login_url = self._build_oauth_url()
|
215
|
+
login_url = self._build_oauth_url(code_verifier, client_id)
|
192
216
|
|
193
217
|
login_soup, _ = await self._session_request("GET", login_url)
|
194
218
|
login_method, login_url = self._get_request_from_soup(login_soup)
|
@@ -196,6 +220,7 @@ class AmazonEchoApi:
|
|
196
220
|
login_inputs["email"] = self._login_email
|
197
221
|
login_inputs["password"] = self._login_password
|
198
222
|
|
223
|
+
_LOGGER.debug("Register at %s", login_url)
|
199
224
|
login_soup, _ = await self._session_request(
|
200
225
|
login_method,
|
201
226
|
login_url,
|
@@ -0,0 +1,9 @@
|
|
1
|
+
aioamazondevices/__init__.py,sha256=Zw6lQsQsOiDmSNnKKCTznWyMHgQ3us0XQsAww3w6YkU,276
|
2
|
+
aioamazondevices/api.py,sha256=0du0a0tWEtT-5sIHIfk8K5Zf0ntIBpYgY3nwER_Pcm4,9735
|
3
|
+
aioamazondevices/const.py,sha256=bZaeO8AeJbDc5hdlbJ3cMwM9teTgYhExSR1oEpRFMLk,1089
|
4
|
+
aioamazondevices/exceptions.py,sha256=tERMur_gry9TmU3UyzndJO_CLViISn4b8ClrRbryFy8,444
|
5
|
+
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
aioamazondevices-0.2.0.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
7
|
+
aioamazondevices-0.2.0.dist-info/METADATA,sha256=ypYsMxLoVYrWxQdLA8cHM0-ysCPWVzIN3yxYxMLs_M8,4680
|
8
|
+
aioamazondevices-0.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
9
|
+
aioamazondevices-0.2.0.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
aioamazondevices/__init__.py,sha256=U15rPzIFIx526iBdCgherokeEZMIr1qB8g-kFW28oIM,276
|
2
|
-
aioamazondevices/api.py,sha256=r8WeERP8FBwzj4gJzwTwem69102Hg6dmz-Q5tJrPJV8,8856
|
3
|
-
aioamazondevices/const.py,sha256=bZaeO8AeJbDc5hdlbJ3cMwM9teTgYhExSR1oEpRFMLk,1089
|
4
|
-
aioamazondevices/exceptions.py,sha256=tERMur_gry9TmU3UyzndJO_CLViISn4b8ClrRbryFy8,444
|
5
|
-
aioamazondevices/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
aioamazondevices-0.1.0.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
|
7
|
-
aioamazondevices-0.1.0.dist-info/METADATA,sha256=wfe_Z0hPTGrccs3lR6eliUWVRzh8M_lMuSL3vIqPHh0,4680
|
8
|
-
aioamazondevices-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
9
|
-
aioamazondevices-0.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|