@@ -33,14 +33,31 @@ def check_status_code(response: requests.Response, url: str) -> None:
3333
3434class ApduResponse :
3535 def __init__ (self , response : requests .Response ) -> None :
36- self .response = response
36+ self .__response = response
3737
38- def receive (self ) -> bytes :
39- check_status_code (self .response , "/apdu" )
40- data , status = split_apdu (bytes .fromhex (self .response .json ()["data" ]))
41- if status != 0x9000 :
42- raise ApduException (status , data )
43- return data
38+ def __receive (self ):
39+ """ Get the response if not yet received and store it in `__data` and `__status` attributes """
40+ if self .__response is not None :
41+ check_status_code (self .__response , "/apdu" )
42+ apdu_message = bytes .fromhex (self .__response .json ()["data" ])
43+ self .__data , self .__status = split_apdu (apdu_message )
44+ self .__response = None
45+
46+ def data (self , expected_sw : int = 0x9000 ) -> bytes :
47+ """
48+ :return: Received data (status word stripped)
49+ :param expected_sw: Expected status word value.
50+ :raises ApduException: If received status word is different from `expected_sw` parameter.
51+ """
52+ self .__receive ()
53+ if self .__status != expected_sw :
54+ raise ApduException (self .__status , self .__data )
55+ return self .__data
56+
57+ def sw (self ) -> int :
58+ """ :return: Received status word """
59+ self .__receive ()
60+ return self .__status
4461
4562
4663def split_apdu (data : bytes ) -> Tuple [bytes , int ]:
@@ -118,13 +135,8 @@ def get_screenshot(self) -> bytes:
118135 check_status_code (response , "/screenshot" )
119136 return response .content
120137
121- def _apdu_exchange (self , data : bytes ) -> bytes :
122- with self .session .post (f"{ self .api_url } /apdu" , json = {"data" : data .hex ()}) as response :
123- apdu_response = ApduResponse (response )
124- return apdu_response .receive ()
125-
126- def _apdu_exchange_nowait (self , data : bytes ) -> requests .Response :
127- return self .session .post (f"{ self .api_url } /apdu" , json = {"data" : data .hex ()}, stream = True )
138+ def _apdu_exchange (self , data : bytes , stream : bool = False ) -> requests .Response :
139+ return self .session .post (f"{ self .api_url } /apdu" , json = {"data" : data .hex ()}, stream = stream )
128140
129141 def set_automation_rules (self , rules : dict ) -> None :
130142 with self .session .post (f"{ self .api_url } /automation" , json = rules ) as response :
@@ -195,9 +207,9 @@ def __init__(self, app: str, args: List[str] = [], api_url: str = "http://127.0.
195207 SpeculosInstance .start (self )
196208 Api .__init__ (self , api_url )
197209
198- def apdu_exchange (self , cla : int , ins : int , data : bytes = b"" , p1 : int = 0 , p2 : int = 0 ) -> bytes :
210+ def apdu_exchange (self , cla : int , ins : int , data : bytes = b"" , p1 : int = 0 , p2 : int = 0 ) -> ApduResponse :
199211 apdu = bytes ([cla , ins , p1 , p2 , len (data )]) + data
200- return Api ._apdu_exchange (self , apdu )
212+ return ApduResponse ( Api ._apdu_exchange (self , apdu ) )
201213
202214 @contextmanager
203215 def apdu_exchange_nowait (
@@ -206,7 +218,7 @@ def apdu_exchange_nowait(
206218 apdu = bytes ([cla , ins , p1 , p2 , len (data )]) + data
207219 response = None
208220 try :
209- response = Api ._apdu_exchange_nowait (self , apdu )
221+ response = Api ._apdu_exchange (self , apdu , stream = True )
210222 yield ApduResponse (response )
211223 finally :
212224 if response :
0 commit comments