Open deweydb opened 1 day ago
can you provide a sample code to reproduce the issue?
Hello, the application is a bit complex, but I have tried to extract out the relevant portion to a single file which reproduces this bug, while removing as much superfluous code as possible. Running the following code on version 2.1.1 results in the error:
Traceback (most recent call last):
File "C:\Users\Adrian\AppData\Local\Programs\Python\Python312\Lib\site-packages\smartcard\CardMonitoring.py", line 165, in run
currentcards = self.cardrequest.waitforcardevent()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Adrian\AppData\Local\Programs\Python\Python312\Lib\site-packages\smartcard\CardRequest.py", line 72, in waitforcardevent
return self.pcsccardrequest.waitforcardevent()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Adrian\AppData\Local\Programs\Python\Python312\Lib\site-packages\smartcard\pcsc\PCSCCardRequest.py", line 321, in waitforcardevent
raise CardRequestException(
smartcard.Exceptions.CardRequestException: Failed to get status change Cannot find a smart card reader. : Cannot find a smart card reader. (0x8010002E)
Running it on version 2.0.10 does not result in such an error.
from smartcard.CardMonitoring import CardObserver, CardMonitor
from smartcard.util import toBytes, toHexString
from smartcard.CardType import ATRCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
from functools import partial
import threading
DEFAULT_WRITER = print
DEFAULT_CARD_ATR = "3B 81 80 01 80 80"
DEFAULT_TIMEOUT = 5.0
class Response:
def __init__(self, raw_response: list):
self.data, sw1, sw2 = raw_response
self.status = sw1, sw2
def is_successful(self):
return self.status in [(0x91, 0x00), (0x90, 0x00), (0x91, 0xAF)]
def to_bytes(self):
return bytearray(self.data)
def to_string(self):
return self.to_bytes().decode("utf-8")
def to_hex_string(self, *args, **kwargs):
return toHexString(self.data, *args, **kwargs)
def dispatch(command: list, service) -> Response:
raw_response = service.connection.transmit(command)
response = Response(raw_response)
return response
class Observer(CardObserver):
def __init__(self, callback=None, auth: dict | None = None, threading_event=None):
self.callback = callback
self.auth = auth
self.threading_event = threading_event
self.send = None
card_type = ATRCardType(toBytes(DEFAULT_CARD_ATR))
card_request = CardRequest(timeout=DEFAULT_TIMEOUT, cardType=card_type)
self.result = None
try:
self.service = card_request.waitforcard()
self.service.connection.connect()
except (CardRequestTimeoutException, CardConnectionException) as e:
return None
def update(self, _, handlers):
added, _ = handlers
if added:
try:
self.send = partial(dispatch, service=self.service)
session_key = self.pre_auth()
self.result = self.callback(
send=self.send, session_key=session_key)
self.service.connection.disconnect()
self.threading_event(self.result)
except CardConnectionException as e:
return None
def pre_auth(self) -> list | None:
if not self.auth:
return None
try:
print("placeholder...")
return "redacted"
except Exception as e:
print(e)
class Omnikey(CardMonitor):
def __init__(self, config=None):
super().__init__()
self.config = config
self.scan_event = threading.Event()
def threading_event_callback(self, result):
self.observer_result = result
self.scan_event.set()
def basic(self, *args, **kwargs):
def decorator(func):
def wrapper():
callback = partial(func, *args, **kwargs)
observer = Observer(
callback=callback, threading_event=self.threading_event_callback
)
self.addObserver(observer)
self.deleteObserver(observer)
return observer.result
return wrapper
return decorator
def authenticate(self, *args, **kwargs):
def decorator(func):
def wrapper():
callback = partial(func, *args, **kwargs)
observer = Observer(
callback=callback,
auth=self.config,
threading_event=self.threading_event_callback,
)
self.addObserver(observer)
self.deleteObserver(observer)
return observer.result
return wrapper
return decorator
omnikey = Omnikey()
@omnikey.basic()
def create_card(**kwargs):
pass
create_card()
I should also add that this bug does not seem to happen on Mac OS, it seems to be exclusive to windows.
I can't reproduce the problem on Windows 10 with the current/unreleased code. I modified a bit your code to add some debug and make it worl with any card.
$ diff -u bug_orig.py bug2.py
--- bug_orig.py 2024-10-09 11:49:54.076068500 +0200
+++ bug2.py 2024-10-09 11:53:37.586248300 +0200
@@ -1,13 +1,11 @@
from smartcard.CardMonitoring import CardObserver, CardMonitor
from smartcard.util import toBytes, toHexString
-from smartcard.CardType import ATRCardType
+from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
from functools import partial
import threading
-DEFAULT_WRITER = print
-DEFAULT_CARD_ATR = "3B 81 80 01 80 80"
DEFAULT_TIMEOUT = 5.0
class Response:
@@ -28,6 +26,7 @@
return toHexString(self.data, *args, **kwargs)
def dispatch(command: list, service) -> Response:
+ print("dispatch")
raw_response = service.connection.transmit(command)
response = Response(raw_response)
return response
@@ -39,7 +38,7 @@
self.auth = auth
self.threading_event = threading_event
self.send = None
- card_type = ATRCardType(toBytes(DEFAULT_CARD_ATR))
+ card_type = AnyCardType
card_request = CardRequest(timeout=DEFAULT_TIMEOUT, cardType=card_type)
self.result = None
@@ -50,6 +49,7 @@
return None
def update(self, _, handlers):
+ print("update:", handlers)
added, _ = handlers
if added:
try:
@@ -63,6 +63,7 @@
return None
def pre_auth(self) -> list | None:
+ print("pre_auth")
if not self.auth:
return None
try:
If I start the program with a card already inserted I immediately get:
update: ([], [])
If I start the program with no card inserted and I insert a card I get:
update: ([3B 6F 00 00 80 5A 28 13 02 10 12 2B 75 11 8E 47 82 90 00 / Alcor Micro USB Smart Card Reader 0], [])
pre_auth
If I start the program with no card inserted and I just wait I get, after 5 seconds:
update: ([], [])
I guess that is the expected behaviour.
Can you install the current code from git and try on your side?
With PySCard 2.1.1 I reproduce your problem. I also see that if I start the test program with a card already inserted I get
update: ([3B 6F 00 00 80 5A 28 13 02 10 12 2B 75 11 8E 47 82 90 00 / Alcor Micro USB Smart Card Reader 0], [])
pre_auth
Instead of an empty added
variable. I will fix that.
Your system information
Please describe your issue in as much detail as possible:
After upgrading from version 2.0.10 to 2.1.1 we have an issue with our Omnikey 5022 USB Reader we receive the following error:
In an effort to try to understand what is going wrong i printed out hresult right before this exception is called and got: -2146435070
Reverting to pyscard 2.0.10 seems to resolve the issue. Please let me know if I can assist in any further tests or debugging of the issue.