Skip to content

Commit

Permalink
Handling errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Flowtter committed Oct 10, 2020
1 parent cdc5d58 commit b2b5f48
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 37 deletions.
47 changes: 47 additions & 0 deletions src/error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class Error(Exception):
"""Base class for exceptions in this module."""
pass


class NoReader(Error):
"""Exception raised when no readers are plug to the computer.
Attributes:
message -- explanation of the error
"""

def __init__(self, message):
self.message = message


class NoCommunication(Error):
"""Exception raised when the communication can't be established.
Attributes:
message -- explanation of the error
"""

def __init__(self, message):
self.message = message


class OptionOutOfRange(Error):
"""Exception raised when you try to access an element not in the `option.options` dictionary
Attributes:
message -- explanation of the error
"""

def __init__(self, message):
self.message = message


class InstructionFailed(Error):
"""Exception raised when the instruction failed
Attributes:
message -- explanation of the error
"""

def __init__(self, message):
self.message = message
112 changes: 75 additions & 37 deletions src/nfc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from smartcard.util import toHexString
from smartcard.ATR import ATR

from src import utils, option
from src import utils, option, error


class Reader:
Expand All @@ -16,37 +16,43 @@ def instantiate_reader():
readers = smartcard.System.readers()

if len(readers) == 0:
raise Exception("No readers available")
raise error.NoReader("No readers available")

reader = readers[0]
c = reader.createConnection()

try:
c.connect()
except:
raise Exception(
raise error.NoCommunication(
"The reader has been deleted and no communication is now possible. Smartcard error code : 0x7FEFFF97"
"\nHint: try to connect a card to the reader")

return reader, c

def command(self, mode, arguments=None):
"""send a payload to the reader
format:
CLA INS P1 P2 P3 Lc Data Le
Format:
CLA INS P1 P2 P3 Lc Data Le
The Le field (optional) indicates the maximum length of the response.
The Lc field indicates the length of the outgoing data.
mandatory:
CLA INS P1 P2
Mandatory:
CLA INS P1 P2
Attributes:
mode: key value of option.options or option.alias
arguments: replace `-1` in the payload by arguments
return the data or sw1 sw2 depending on the request"""
Returns:
return the data or sw1 sw2 depending on the request"""
mode = option.alias.get(mode) or mode
payload = option.options.get(mode)

if not payload:
raise Exception("Option do not exist\nHint: try to call help(nfc.Reader().command) to see all options")
raise error.OptionOutOfRange("Option do not exist\nHint: try to call help(nfc.Reader().command) to see all options")

payload = utils.replace_arguments(payload, arguments)
result = self.connection.transmit(payload)
Expand All @@ -57,7 +63,7 @@ def command(self, mode, arguments=None):
data, n, sw1, sw2 = result

if [sw1, sw2] == option.answers.get("fail"):
raise Exception(f"Instruction {mode} failed")
raise error.InstructionFailed(f"Instruction {mode} failed")

print(f"success: {mode}")
if data:
Expand All @@ -66,6 +72,21 @@ def command(self, mode, arguments=None):
if [sw1, sw2] != option.answers.get("success"):
return sw1, sw2

def custom(self, payload):
"""send a custom payload to the reader
Format:
CLA INS P1 P2 P3 Lc Data Le"""
result = self.connection.transmit(payload)

if len(result) == 3:
data, sw1, sw2 = result
else:
data, n, sw1, sw2 = result

if [sw1, sw2] == option.answers.get("fail"):
raise error.InstructionFailed(f"Payload {payload} failed")

def get_uid(self):
"""get the uid of the card"""
return self.command("get_uid")
Expand All @@ -77,52 +98,62 @@ def firmware_version(self):
def load_authentication_data(self, key_location, key_value):
"""load the authentication key
@key location : 0x00 ~ 0x01
@key value : 6 bytes
Attributes:
key location : 0x00 ~ 0x01
key value : 6 bytes
E.g. 0x01, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]"""
Example:
E.g. 0x01, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]"""
self.command("load_authentication_data", [key_location, key_value])

def authentication(self, bloc_number, key_type, key_location):
"""authentication with the key in `load_authentication_data`
@block number : 1 byte
@key type A/B : 0x60 ~ 0x61
@key location : 0x00 ~ 0x01
Attributes:
block number : 1 byte
key type A/B : 0x60 ~ 0x61
key location : 0x00 ~ 0x01
E.g. 0x00, 0x61, 0x01"""
Example:
E.g. 0x00, 0x61, 0x01"""
self.command("authentication", [bloc_number, key_type, key_location])

def read_binary_blocks(self, block_number, number_of_byte_to_read):
"""read n bytes in the card at the block_number index
@block number : 1 byte
@number of Bytes to read : 1
Attributes:
block number : 1 byte
number of Bytes to read : 1
E.g. 0x00, 0x02"""
Example:
E.g. 0x00, 0x02"""
return self.command("read_binary_blocks", [block_number, number_of_byte_to_read])

def update_binary_blocks(self, block_number, number_of_byte_to_update, block_data):
"""update n bytes in the card with block_data at the block_number index
@block number : 1 byte
@number of Bytes to update : 1-16 bytes
@block data : 4-16 bytes
Attributes:
block number : 1 byte
number of Bytes to update : 1-16 bytes
block data : 4-16 bytes
E.g. 0x01, 0x10, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05
0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15]"""
Examples:
0x01, 0x10, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05
0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15]"""
self.command("update_binary_blocks", [block_number, number_of_byte_to_update, block_data])

def led_control(self, led_state, t1, t2, number_of_repetition, link_to_buzzer):
"""control led state
@led state control : 0x00 - 0x0F
@T1 led Duration
@T2 led Duration
@number of repetition
@link to buzzer
Attributes:
led state control : 0x00 - 0x0F
T1 led Duration
T2 led Duration
number of repetition
link to buzzer
E.g. 0x05, 0x01, 0x01, 0x01, 0x01"""
Example:
0x05, 0x01, 0x01, 0x01, 0x01"""
self.command("led_control", [led_state, t1, t2, number_of_repetition, link_to_buzzer])

def get_picc_version(self):
Expand All @@ -132,28 +163,35 @@ def get_picc_version(self):
def set_picc_version(self, picc_value):
"""set the PICC version of the reader
@PICC value: 1 byte, default is 0xFF
Attributes:
PICC value: 1 byte, default is 0xFF
E.g. 0xFF"""
Example:
0xFF"""
self.command("set_picc_version", [picc_value])

def buzzer_sound(self, poll_buzzer_status):
"""set the buzzer sound state
@poll buzz status : 0x00 ~ 0xFF
Attributes:
poll buzz status : 0x00 ~ 0xFF
E.g. 0x00"""
Example:
0x00"""
self.command("buzzer_sound", [poll_buzzer_status])

def set_timeout(self, timeout_parameter):
"""set the timeout of the reader
timeout parameter : 0x00 ~ 0x01 - 0xFE ~ 0xFF : (0, 5 second unit, infinite), default is 0xFF
Attributes:
timeout parameter : 0x00 ~ 0x01 - 0xFE ~ 0xFF : (0, 5 second unit, infinite), default is 0xFF
E.g. 0x01"""
Example:
0x01"""
self.command("set_timeout", [timeout_parameter])

def info(self):
"""print the type of the card on the reader"""
atr = ATR(self.connection.getATR())
historical_byte = toHexString(atr.getHistoricalBytes(), 0)
print(historical_byte)
Expand Down

0 comments on commit b2b5f48

Please sign in to comment.