aioamazondevices 0.1.1__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.
@@ -1,6 +1,6 @@
1
1
  """aioamazondevices library."""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.2.0"
4
4
 
5
5
 
6
6
  from .api import AmazonDevice, AmazonEchoApi
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,6 +48,7 @@ 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
54
  # Force country digits as lower case
@@ -85,11 +66,32 @@ class AmazonEchoApi:
85
66
  self._login_password = login_password
86
67
  self._domain = domain
87
68
  self._url = f"https://www.amazon.{domain}"
88
- self._cookies = _build_init_cookies()
69
+ self._cookies = self._build_init_cookies()
89
70
  self._headers = DEFAULT_HEADERS
71
+ self._save_html = save_html
90
72
 
91
73
  self.session: AsyncClient
92
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
+
93
95
  def _create_code_verifier(self, length: int = 32) -> bytes:
94
96
  """Create code verifier."""
95
97
  verifier = secrets.token_bytes(length)
@@ -100,18 +102,18 @@ class AmazonEchoApi:
100
102
  m = hashlib.sha256(verifier)
101
103
  return base64.urlsafe_b64encode(m.digest()).rstrip(b"=")
102
104
 
103
- def _build_client_id(self) -> str:
105
+ def _build_client_id(self, serial: str) -> str:
104
106
  """Build client ID."""
105
- serial = uuid.uuid4().hex.upper()
106
107
  client_id = serial.encode() + AMAZON_SERIAL_NUMBER
107
108
  return client_id.hex()
108
109
 
109
110
  def _build_oauth_url(
110
111
  self,
112
+ code_verifier: bytes,
113
+ client_id: str,
111
114
  ) -> str:
112
115
  """Build the url to login to Amazon as a Mobile device."""
113
- client_id = self._build_client_id()
114
- code_challenge = self._create_s256_code_challenge(self._create_code_verifier())
116
+ code_challenge = self._create_s256_code_challenge(code_verifier)
115
117
 
116
118
  oauth_params = {
117
119
  "openid.oa2.response_type": "code",
@@ -183,15 +185,34 @@ class AmazonEchoApi:
183
185
  url,
184
186
  data=input_data,
185
187
  )
188
+
189
+ await self._save_to_file(
190
+ resp.text,
191
+ url,
192
+ )
186
193
  return BeautifulSoup(resp.content, "html.parser"), resp
187
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
+
188
206
  async def login(self, otp_code: str) -> bool:
189
207
  """Login to Amazon."""
190
208
  _LOGGER.debug("Logging-in for %s [otp code %s]", self._login_email, otp_code)
191
209
  self._client_session()
192
210
 
211
+ code_verifier = self._create_code_verifier()
212
+ client_id = self._build_client_id(uuid.uuid4().hex.upper())
213
+
193
214
  _LOGGER.debug("Build oauth URL")
194
- login_url = self._build_oauth_url()
215
+ login_url = self._build_oauth_url(code_verifier, client_id)
195
216
 
196
217
  login_soup, _ = await self._session_request("GET", login_url)
197
218
  login_method, login_url = self._get_request_from_soup(login_soup)
@@ -199,6 +220,7 @@ class AmazonEchoApi:
199
220
  login_inputs["email"] = self._login_email
200
221
  login_inputs["password"] = self._login_password
201
222
 
223
+ _LOGGER.debug("Register at %s", login_url)
202
224
  login_soup, _ = await self._session_request(
203
225
  login_method,
204
226
  login_url,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aioamazondevices
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Python library to control Amazon devices
5
5
  Home-page: https://github.com/chemelli74/aioamazondevices
6
6
  License: Apache Software License 2.0
@@ -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=SuObz0aaV65dnO31xiBGb_haUxDDGXws2ymCzUMqY3U,276
2
- aioamazondevices/api.py,sha256=CmPKA68a53zs0DuirAnV3UaJEaSLk3Ibz6KBEgJCufk,8934
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.1.dist-info/LICENSE,sha256=sS48k5sp9bFV-NSHDfAJuTZZ_-AP9ZDqUzQ9sffGlsg,11346
7
- aioamazondevices-0.1.1.dist-info/METADATA,sha256=8Ha1ublO8rQgFJuOWq0ur8zhAKzNCYgdVS4KplWbnO8,4680
8
- aioamazondevices-0.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
9
- aioamazondevices-0.1.1.dist-info/RECORD,,