ragger 1.41.2__py3-none-any.whl → 1.42.1__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.
- ragger/__version__.py +2 -2
- ragger/backend/speculos.py +27 -2
- ragger/conftest/base_conftest.py +3 -2
- {ragger-1.41.2.dist-info → ragger-1.42.1.dist-info}/METADATA +1 -1
- {ragger-1.41.2.dist-info → ragger-1.42.1.dist-info}/RECORD +8 -8
- {ragger-1.41.2.dist-info → ragger-1.42.1.dist-info}/WHEEL +1 -1
- {ragger-1.41.2.dist-info → ragger-1.42.1.dist-info}/licenses/LICENSE +0 -0
- {ragger-1.41.2.dist-info → ragger-1.42.1.dist-info}/top_level.txt +0 -0
ragger/__version__.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.
|
|
32
|
-
__version_tuple__ = version_tuple = (1,
|
|
31
|
+
__version__ = version = '1.42.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 42, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
ragger/backend/speculos.py
CHANGED
|
@@ -120,6 +120,7 @@ class SpeculosBackend(BackendInterface):
|
|
|
120
120
|
api_url=self.url,
|
|
121
121
|
**kwargs)
|
|
122
122
|
self._pending: Optional[ApduResponse] = None
|
|
123
|
+
self._pending_async_response: Optional[ApduResponse] = None
|
|
123
124
|
self._last_screenshot: Optional[BytesIO] = None
|
|
124
125
|
self._home_screenshot: Optional[BytesIO] = None
|
|
125
126
|
self._ticker_paused_count = 0
|
|
@@ -137,6 +138,15 @@ class SpeculosBackend(BackendInterface):
|
|
|
137
138
|
def apdu_timeout(self, value: float) -> None:
|
|
138
139
|
self._apdu_timeout = value
|
|
139
140
|
|
|
141
|
+
def _check_async_error(self) -> None:
|
|
142
|
+
"""Check for async APDU errors and raise if present."""
|
|
143
|
+
if self._pending_async_response is not None and self._last_async_response is None:
|
|
144
|
+
if has_data_available(self._pending_async_response, timeout=0):
|
|
145
|
+
self.logger.info("[Ragger] Early async data available, retrieving it now.")
|
|
146
|
+
# This will raise ExceptionRAPDU immediately if status != 9000
|
|
147
|
+
self._last_async_response = self._get_last_async_response(
|
|
148
|
+
self._pending_async_response)
|
|
149
|
+
|
|
140
150
|
def _retrieve_client_screen_content(self) -> dict:
|
|
141
151
|
raw_content = self._client.get_current_screen_content()
|
|
142
152
|
# Keep only text events
|
|
@@ -214,13 +224,22 @@ class SpeculosBackend(BackendInterface):
|
|
|
214
224
|
@contextmanager
|
|
215
225
|
def exchange_async_raw(self, data: bytes = b"") -> Generator[bool, None, None]:
|
|
216
226
|
self.apdu_logger.info("=> %s", data.hex())
|
|
227
|
+
# Reset state for this new async exchange
|
|
228
|
+
self._last_async_response = None
|
|
217
229
|
with self._client.apdu_exchange_nowait(cla=data[0],
|
|
218
230
|
ins=data[1],
|
|
219
231
|
p1=data[2],
|
|
220
232
|
p2=data[3],
|
|
221
233
|
data=data[5:]) as response:
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
self._pending_async_response = response
|
|
235
|
+
try:
|
|
236
|
+
yield has_data_available(response, timeout=self.apdu_timeout)
|
|
237
|
+
# Only retrieve if not already retrieved by _check_async_error during navigation
|
|
238
|
+
if self._last_async_response is None:
|
|
239
|
+
self._last_async_response = self._get_last_async_response(response)
|
|
240
|
+
finally:
|
|
241
|
+
# Clear pending async response flag in all cases
|
|
242
|
+
self._pending_async_response = None
|
|
224
243
|
|
|
225
244
|
def right_click(self) -> None:
|
|
226
245
|
self._client.press_and_release("right")
|
|
@@ -315,6 +334,12 @@ class SpeculosBackend(BackendInterface):
|
|
|
315
334
|
if not screenshot_equal(screenshot, self._last_screenshot):
|
|
316
335
|
break
|
|
317
336
|
|
|
337
|
+
# Check for async APDU errors before sending a tick. This ensures that if the
|
|
338
|
+
# application has already refused the APDU (e.g., due to an error), we detect and raise
|
|
339
|
+
# the error immediately instead of waiting for a screen change that will never occur.
|
|
340
|
+
# This makes navigation robust and prevents hanging.
|
|
341
|
+
self._check_async_error()
|
|
342
|
+
|
|
318
343
|
# Send a ticker event and let the app process it
|
|
319
344
|
self.send_tick()
|
|
320
345
|
screenshot = BytesIO(self._client.get_screenshot())
|
ragger/conftest/base_conftest.py
CHANGED
|
@@ -283,8 +283,9 @@ def prepare_speculos_args(root_pytest_dir: Path,
|
|
|
283
283
|
)
|
|
284
284
|
main_app_path = find_application(app_dir_subdirectories[0], device_name, "c")
|
|
285
285
|
|
|
286
|
-
# This repo holds the library, not the standalone app: search in
|
|
287
|
-
lib_path = find_application(project_root_dir
|
|
286
|
+
# This repo holds the library, not the standalone app: search in build_directory
|
|
287
|
+
lib_path = find_application(project_root_dir / manifest.app.build_directory, device_name,
|
|
288
|
+
manifest.app.sdk)
|
|
288
289
|
speculos_args.append(f"-l{lib_path}")
|
|
289
290
|
# If the app is standalone, the main app should be located in project_root_dir / manifest.app.build_directory
|
|
290
291
|
else:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
ragger/__init__.py,sha256=Vbk78M7VtDVMTu02zYQquYSTxtgbieknkvr3uXONrig,713
|
|
2
|
-
ragger/__version__.py,sha256=
|
|
2
|
+
ragger/__version__.py,sha256=0mWI4xQoxal_8S_OmewzeMGCk0Sffbe_ECmk0NOV1QU,706
|
|
3
3
|
ragger/error.py,sha256=mmeipucrlUz1g1kkNy15rXpCccpzucnRTGIsKbcOzBo,6528
|
|
4
4
|
ragger/logger.py,sha256=XF3DsHDLGOHAG7cqVj_7BQlHKj9J8zw8A9soFHIydc8,2457
|
|
5
5
|
ragger/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -8,13 +8,13 @@ ragger/backend/interface.py,sha256=P_Uk0qXz8xrgy9m6mMaY7HWz_gg9dlYvarjmYpv_6EQ,2
|
|
|
8
8
|
ragger/backend/ledgercomm.py,sha256=XhG2GszkfjrJTPAECqUJ35PCkDs9mHnVn4ThbQZhQPg,3882
|
|
9
9
|
ragger/backend/ledgerwallet.py,sha256=b8p6vTPCddAfIk9uT9bJbPqE8e4UqfL3w10ufqPdROc,3733
|
|
10
10
|
ragger/backend/physical_backend.py,sha256=Y5BRhsKliqCyYFFce7D7swRlT3dkwsXptrUq3zm2Oks,5955
|
|
11
|
-
ragger/backend/speculos.py,sha256=
|
|
11
|
+
ragger/backend/speculos.py,sha256=nQjvzSd0uCRt6tkJjPcjQVM2msBMkF8u7fqk1p-QCFk,17629
|
|
12
12
|
ragger/backend/stub.py,sha256=OIn4pIdnBuhgmCAAjGlVTEuWtaCLyCtVLVO-VTAEBRs,3284
|
|
13
13
|
ragger/bip/__init__.py,sha256=7gY5V8gkJfct1g4OgaLg8bNpgoITGaqU9gTKC4tHbAM,920
|
|
14
14
|
ragger/bip/path.py,sha256=uX69L3U8vteIHJy_PE5yPloGaiiYYMq_jLbBSENiRqs,1709
|
|
15
15
|
ragger/bip/seed.py,sha256=yKGM_fkFCh6hNAl7vOMrEv5kEoQoDmVPhBCIMtO8dNk,1758
|
|
16
16
|
ragger/conftest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
ragger/conftest/base_conftest.py,sha256=
|
|
17
|
+
ragger/conftest/base_conftest.py,sha256=r3MuOMDsI3Q5ZiUs4S0TlcyqYT8BeCrWImXjQOXTmN8,20831
|
|
18
18
|
ragger/conftest/configuration.py,sha256=jE_zbvDWSc7jQQ4VEJBo8m_3kME09i2YXK6PLigPAes,3297
|
|
19
19
|
ragger/firmware/__init__.py,sha256=3g_-n2b0qEgVlP42lOQiZzBPux6PCUtZnydkQeEn_Vk,687
|
|
20
20
|
ragger/firmware/structs.py,sha256=pkUzEkq-kiUntWK2mt1Vkalgoe-3tbvBcLfe12L-CNo,1804
|
|
@@ -50,8 +50,8 @@ ragger/utils/__init__.py,sha256=PUabSv1qx0XyKWovIxvGBI71sd3O3bKp3gCsUxlWm1E,997
|
|
|
50
50
|
ragger/utils/misc.py,sha256=Gx1LbtaOh3ns8C_4sRJAFyym2RcbTEmjNtjRfHT_BYw,6851
|
|
51
51
|
ragger/utils/packing.py,sha256=2xaRR-FhwVfknP74ZGo-O4JTE6R0HpNqhxKJ9aMrns4,766
|
|
52
52
|
ragger/utils/structs.py,sha256=JMfuX5u-4gSZfqH0SER05B15-mj0YyHjnxLAgxAYtAM,1413
|
|
53
|
-
ragger-1.
|
|
54
|
-
ragger-1.
|
|
55
|
-
ragger-1.
|
|
56
|
-
ragger-1.
|
|
57
|
-
ragger-1.
|
|
53
|
+
ragger-1.42.1.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
54
|
+
ragger-1.42.1.dist-info/METADATA,sha256=dTcZ-2aynRqePhA93nHelHWskURVRN71CCelSLk3jv8,10660
|
|
55
|
+
ragger-1.42.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
56
|
+
ragger-1.42.1.dist-info/top_level.txt,sha256=kqJEoAZ6qn0T3iuVa-710gBK7Ik1euCwNwBbyFraRQg,7
|
|
57
|
+
ragger-1.42.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|