sonnenbatterie 0.7.dev3__tar.gz → 0.7.dev4__tar.gz
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.
- {sonnenbatterie-0.7.dev3/sonnenbatterie.egg-info → sonnenbatterie-0.7.dev4}/PKG-INFO +1 -1
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/setup.cfg +1 -1
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie/sonnenbatterie.py +55 -30
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4/sonnenbatterie.egg-info}/PKG-INFO +1 -1
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/LICENSE +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/README.md +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/pyproject.toml +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/setup.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie/__init__.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie/const.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie.egg-info/SOURCES.txt +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie.egg-info/dependency_links.txt +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie.egg-info/requires.txt +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie.egg-info/top_level.txt +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie2/__init__.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie2/const.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie2/sonnenbatterie2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_api_v1.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_api_v2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_battery_reserve.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_battery_reserve_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_operating_mode.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_operating_mode_api_v2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_operating_mode_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_operating_mode_async_api_v2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_retrieval_loop.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_set_flow.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_set_flow_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_set_flow_v2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_set_flow_v2_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_timeofuse.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_timeofuse_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_timeofuse_lib.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_timeofuse_v2.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_timeofuse_v2_async.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/timeofuse/__init__.py +0 -0
- {sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/timeofuse/timeofuse.py +0 -0
|
@@ -295,46 +295,71 @@ class AsyncSonnenBatterie:
|
|
|
295
295
|
if saltResponseCode!=200: #use old variant where no salt is availlable
|
|
296
296
|
#Old path (no salt): PBKDF2 over sha512(password) + challenge → hex
|
|
297
297
|
response=hashlib.pbkdf2_hmac('sha512',pw_sha512.encode('utf-8'),challenge.encode('utf-8'),7500,64).hex()
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if len(salt_str) % 2 == 0 and all(c in string.hexdigits for c in salt_str):
|
|
303
|
-
salt_bytes = bytes.fromhex(salt_str)
|
|
304
|
-
else:
|
|
305
|
-
raise ValueError
|
|
306
|
-
except Exception:
|
|
307
|
-
try:
|
|
308
|
-
salt_bytes = base64.b64decode(salt_str, validate=True)
|
|
309
|
-
except Exception:
|
|
310
|
-
salt_bytes = salt_str.encode("utf-8")
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
dk = hashlib.pbkdf2_hmac(
|
|
314
|
-
"sha512",
|
|
315
|
-
self.password.encode("utf-8"), # raw password (not pre-hashed)
|
|
316
|
-
salt_bytes,
|
|
317
|
-
7500,
|
|
318
|
-
dklen=64
|
|
298
|
+
session = await self._session.post(
|
|
299
|
+
url = self.baseurl+'session',
|
|
300
|
+
data = {"user":self.username,"challenge":challenge,"response":response},
|
|
301
|
+
timeout=self._timeout,
|
|
319
302
|
)
|
|
320
|
-
|
|
303
|
+
session.raise_for_status()
|
|
304
|
+
token = await session.json()
|
|
305
|
+
self.token = token['authentication_token']
|
|
306
|
+
else:#New path (with salt): PBKDF2 over password + salt → HMAC-SHA256(challenge) → hex.
|
|
307
|
+
await create_session_token_new()
|
|
321
308
|
|
|
322
309
|
|
|
323
310
|
|
|
324
|
-
session = await self._session.post(
|
|
325
|
-
url = self.baseurl+'session',
|
|
326
|
-
data = {"user":self.username,"challenge":challenge,"response":response},
|
|
327
|
-
timeout=self._timeout,
|
|
328
|
-
)
|
|
329
|
-
session.raise_for_status()
|
|
330
|
-
token = await session.json()
|
|
331
|
-
self.token = token['authentication_token']
|
|
332
311
|
|
|
333
312
|
# Inisitalite async API v2
|
|
334
313
|
if self.sb2 is None:
|
|
335
314
|
self.sb2 = AsyncSonnenBatterieV2(ip_address=self.ipaddress, api_token=self.token)
|
|
336
315
|
|
|
337
316
|
|
|
317
|
+
async def create_session_token_new(self):
|
|
318
|
+
# Step 1: challenge
|
|
319
|
+
async with self._session.get(f"{self.baseurl}challenge") as r:
|
|
320
|
+
r.raise_for_status()
|
|
321
|
+
try:
|
|
322
|
+
challenge = await r.json()
|
|
323
|
+
if isinstance(challenge, dict):
|
|
324
|
+
challenge = challenge.get("challenge") or next(iter(challenge.values()))
|
|
325
|
+
except Exception:
|
|
326
|
+
challenge = (await r.text()).strip()
|
|
327
|
+
|
|
328
|
+
# Step 2: salt
|
|
329
|
+
async with self._session.get(f"{self.baseurl}salt/{self.username}") as r:
|
|
330
|
+
r.raise_for_status()
|
|
331
|
+
salt = (await r.json())["salt"]
|
|
332
|
+
|
|
333
|
+
# Step 3: derive key
|
|
334
|
+
pw_sha512_hex = hashlib.sha512(self.password.encode("utf-8")).hexdigest()
|
|
335
|
+
pw_bytes = pw_sha512_hex.encode("utf-8")
|
|
336
|
+
dk = hashlib.pbkdf2_hmac("sha512", pw_bytes, salt.encode("utf-8"), 7500, dklen=64)
|
|
337
|
+
derived_hex = dk.hex()
|
|
338
|
+
|
|
339
|
+
# Step 4: loop: POST /session, maybe retry with new_challenge
|
|
340
|
+
for _ in range(2):
|
|
341
|
+
key = derived_hex.encode("utf-8")
|
|
342
|
+
response = hmac.new(key, challenge.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
343
|
+
payload = {"user": self.username, "challenge": challenge, "response": response}
|
|
344
|
+
|
|
345
|
+
async with self._session.post(f"{self.baseurl}session", json=payload) as r:
|
|
346
|
+
r.raise_for_status()
|
|
347
|
+
data = await r.json()
|
|
348
|
+
|
|
349
|
+
if "new_challenge" in data and data["new_challenge"]:
|
|
350
|
+
challenge = data["new_challenge"]
|
|
351
|
+
continue
|
|
352
|
+
|
|
353
|
+
if "authentication_token" in data and data["authentication_token"]:
|
|
354
|
+
self.token = data["authentication_token"]
|
|
355
|
+
|
|
356
|
+
raise RuntimeError(f"Unexpected /session response: {json.dumps(data)}")
|
|
357
|
+
|
|
358
|
+
raise RuntimeError("Failed to obtain authentication_token")
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
338
363
|
""" Base functions """
|
|
339
364
|
|
|
340
365
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/sonnenbatterie.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sonnenbatterie-0.7.dev3 → sonnenbatterie-0.7.dev4}/test/test_operating_mode_async_api_v2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|