fix(python): allow `client.ensure_unlocked()` to proceed on an uninitialized device
What changed, and why it matters
This commit fixes a Python library helper so that checking whether a Trezor device is unlocked no longer crashes or misbehaves when the device is brand new and not yet set up. It adds a guard that returns early if the device is uninitialized, because an uninitialized device has no wallet and therefore cannot be 'locked' in the usual sense. The change is accompanied by a docstring clarifying that the lower-level session method only works on initialized devices with a passphrase.
No immediate security action required. Treat as a normal bugfix. Users of the Python library who call ensure_unlocked() on fresh or factory-reset devices will now get graceful behavior instead of an error. Review downstream callers to confirm they handle the uninitialized case appropriately.
Security signals we found
defensive guard added for uninitialized state
prevention of unexpected exception/call failure in library helper
docstring clarifies precondition for passphrase-derived session
Evidence from the diff
In python/src/trezorlib/client.py, the TrezorClient.ensure_unlocked() method now checks self.features.initialized and returns immediately if the device is uninitialized. Previously, it would call get_session(passphrase=PassphraseSetting.STANDARD_WALLET) and then session.ensure_unlocked(), which derives a root fingerprint via GET_ROOT_FINGERPRINT_MESSAGE. On an uninitialized device there is no seed/passphrase, so that flow would fail. The Session.ensure_unlocked() docstring was also added to document that it requires a passphrase-derived session and thus an initialized device. The fix is defensive and local; it does not change device firmware behavior.
Changed components
python/src/trezorlib/client.pyTrezorClient.ensure_unlocked()Session.ensure_unlocked()Inspect captured patch +11 / −0
diff --git a/python/src/trezorlib/client.py b/python/src/trezorlib/client.py
index 2a3b7ac0..8fa61098 100644
--- a/python/src/trezorlib/client.py
+++ b/python/src/trezorlib/client.py
@@ -172,6 +172,14 @@ class Session(t.Generic[ClientType, SessionIdType]):
@enter_context
def ensure_unlocked(self) -> None:
+ """Ensure that the device is unlocked.
+
+ This method only works on sessions that have a passphrase derived, and
+ transitively, only on an initialized device.
+
+ Go through `client.ensure_unlocked()` if you want to abstract away the
+ choice of a correct session for this operation.
+ """
resp = self.call(GET_ROOT_FINGERPRINT_MESSAGE, expect=messages.PublicKey)
assert resp.root_fingerprint is not None
root_fingerprint = resp.root_fingerprint.to_bytes(4, "big")
@@ -560,6 +568,9 @@ class TrezorClient(t.Generic[SessionType], metaclass=ABCMeta):
def ensure_unlocked(self) -> None:
"""Ensure the device is unlocked."""
+ if not self.features.initialized:
+ # uninitialized device cannot be locked
+ return
session = self.get_session(passphrase=PassphraseSetting.STANDARD_WALLET)
with session:
session.ensure_unlocked()
Why this scored 30/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.