|
2 | 2 |
|
3 | 3 | from collections.abc import AsyncGenerator |
4 | 4 | from contextlib import asynccontextmanager |
5 | | -import hashlib |
6 | 5 |
|
7 | | -from httpx import AsyncClient, DigestAuth, Request, Response |
8 | | -from httpx._auth import _DigestAuthChallenge |
| 6 | +from httpx import AsyncClient, DigestAuth, Response |
9 | 7 | from pyprusalink.types import Conflict, InvalidAuth, NotFound |
10 | 8 |
|
11 | 9 |
|
12 | | -# TODO remove after the following issues are fixed (in all supported firmwares for the latter one): |
13 | | -# https://github.com/encode/httpx/pull/3045 |
14 | | -# https://github.com/prusa3d/Prusa-Firmware-Buddy/pull/3665 |
15 | | -class DigestAuthWorkaround(DigestAuth): |
16 | | - """Wrapper for httpx.DigestAuth to work around a firmware issue.""" |
17 | | - |
18 | | - # Taken from httpx.DigestAuth and modified |
19 | | - # https://github.com/encode/httpx/blob/c6907c22034e2739c4c1af89908e3c9f90602788/httpx/_auth.py#L258 |
20 | | - def _build_auth_header( |
21 | | - self, request: Request, challenge: "_DigestAuthChallenge" |
22 | | - ) -> str: |
23 | | - if challenge.qop is not None: |
24 | | - return super()._build_auth_header(request, challenge) |
25 | | - |
26 | | - def digest(data: bytes) -> bytes: |
27 | | - return hashlib.md5(data).hexdigest().encode() |
28 | | - |
29 | | - A1 = b":".join((self._username, challenge.realm, self._password)) |
30 | | - HA1 = digest(A1) |
31 | | - |
32 | | - path = request.url.raw_path |
33 | | - A2 = b":".join((request.method.encode(), path)) |
34 | | - HA2 = digest(A2) |
35 | | - |
36 | | - digest_data = [HA1, challenge.nonce, HA2] |
37 | | - |
38 | | - format_args = { |
39 | | - "username": self._username, |
40 | | - "realm": challenge.realm, |
41 | | - "nonce": challenge.nonce, |
42 | | - "uri": path, |
43 | | - "response": digest(b":".join(digest_data)), |
44 | | - # Omitting algorithm as a work around for https://github.com/prusa3d/Prusa-Firmware-Buddy/pull/3665 |
45 | | - } |
46 | | - |
47 | | - return "Digest " + self._get_header_value(format_args) |
48 | | - |
49 | | - |
50 | 10 | class ApiClient: |
51 | 11 | def __init__( |
52 | 12 | self, async_client: AsyncClient, host: str, username: str, password: str |
53 | 13 | ) -> None: |
54 | 14 | self._async_client = async_client |
55 | 15 | self.host = host |
56 | | - self._auth = DigestAuthWorkaround(username=username, password=password) |
| 16 | + self._auth = DigestAuth(username=username, password=password) |
57 | 17 |
|
58 | 18 | @asynccontextmanager |
59 | 19 | async def request( |
|
0 commit comments