@paddek/smartcard
v1.0.2
Published
Changes: * more flexible (hopefully) see: **Class: Devices constructor** * events for card detection, card leaving and state change for better control * depends on [PaddeK's](https://github.com/paddek) fork of [pcsclite](https://github.com/paddek/node-
Downloads
8
Maintainers
Readme
Fork of tomkp's smartcard library.
Changes:
- more flexible (hopefully) see: Class: Devices constructor
- events for card detection, card leaving and state change for better control
- depends on PaddeK's fork of pcsclite which fixes node v12 compilation errors and warnings
smartcard
This is a simple wrapper around Santiago Gimeno's great pcsclite library.
Used by Card Spy
API
The following objects are defined by the smartcard
library, each contains its own set of methods and events.
Class: Devices
A general object that provides access to all smartcard related devices.
Events
The devices
object emits the following events
Event: 'device-activated'
Emitted when a card reader is attached. Returns:
Object
Device
Array
: List of all devices, returned viadevices.listDevices()
Event: 'device-deactivated'
Emitted when a card reader is detached. Returns:
Object
Device
Array
: List of all devices, returned viadevices.listDevices()
Event: 'error'
Emitted when an error occurs
Returns Object
:
- error
Error
Methods
The following methods are available within the devices
class.
Constructor Devices(options)
The constructor for a devices object takes one optional argument.
- options
Object
- shareMode
Number
(optional): The shareMode the autoConnect uses (default: SCARD_SHARE_SHARED) - disposition
Number
(optional): The disposition the autoDisconnect uses (default: SCARD_LEAVE_CARD) - autoConnect
Boolean
(optional): Auto connect after card-detected event (default: true) - autoDisconnect
Boolean
(optional): Auto disconnect after card-left event (default: true) - isCardInserted
Function
(optional): Function to determine if card is inserted (default: preserve smartcard behaviour) - isCardRemoved
Function
(optional): Function to determine if card is removed (default: preserve smartcard behaviour)
- shareMode
devices.listDevices()
Returns Object
a list of the different devices attached, each a device
object
devices.lookup(name)
- name
String
: The text name of a device
Class: Device
An object representing a specific card reader (device).
Methods
The following methods are available within the device
class.
device.getCard()
Returns the Card
inserted in the attached device.
device.getName()
Returns the name of the attached device.
device.getStatus()
Returns the current status of the attached device.
device.connect(options)
Connects to attached device and sets reference to inserted Card
.
- options
Object
- share_mode
Number
(optional): The share mode to use (default: SCARD_SHARE_EXCLUSIVE) - protocol
Number
(optional): The prefered protocol (default: SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
- share_mode
Returns Promise
- Resolves with event
Object
- Rejects with error
Error
device.disconnect(disposition)
Disconnect from attached device and remove reference to inserted Card
.
- disposition
Number
(optional): The share mode to use (default: SCARD_UNPOWER_CARD)
Returns Promise
- Resolves with event
Object
- Rejects with error
Error
device.transmit(data, res_len, protocol, cb)
Sends a command to the connected device
- data
Buffer
: data to be transmitted - res_len
Number
: Maximum length of the expected response, includes the 2 byte response (sw1 and sw2) - protocol
Number
: Protocol to be used in the transmission
Returns Promise
- Resolves with response
Buffer
- Rejects with error
Error
Events
The device
object emits the following events
Event: 'card-inserted'
Emitted when a smartcard is inserted into a card reader
Returns Object
:
- device
Device
- protocol
Number
- card
Card
Event: 'card-removed'
Emitted when a smartcard is removed from a card reader
Returns Object
:
- name
String
- card
Card
Event: 'card-detected'
Emitted when a smartcard is about to be inserted into a card reader
Returns Object
:
- state
Number
- atr
String
Event: 'status'
Emitted when the state of a card reader changes
Returns Object
:
- state
Number
- atr
String
Event: 'card-left'
Emitted when a smartcard is about to be removed from a card reader
Returns Object
:
- state
Number
- atr
String
Class: Card
An object representing an attached smart card.
Methods
The following methods are available within the card
class.
card.getAtr()
Returns String
containing the atr of the card
card.issueCommand(commandApdu)
Sends a command to the card
- commandApdu: The command to be sent to the card
String
Buffer
Array
CommandApdu
Returns Promise
- Resolves with response
Buffer
- Rejects with error
Error
If no callback is specified, returns a Promise
*
Events
The card
object emits the following events
Event: 'command-issued'
Emitted when a command is sent to the smartcard.
Returns Object
:
- card
Card
- command
CommandApdu
Event: 'response-received'
Emitted when a response is received from the card.
Returns Object
:
- card
Card
- command
CommandApdu
- response
ResponseApdu
Class: CommandApdu
An object representing a command to send to a smart card
Methods
The CommandApdu
class has the following methods.
Constructor CommandApdu(obj)
Creates a new instance and sets the appropriate items
- obj
Object
- cla
Number
: The class of the command, typically 0 - ins
Number
: The instruction - p1
Number
: The value of p1 - p2
Number
: The value of p2 - data
Array
(optional): The value of data - le
Number
(optional): The value of le
- cla
OR
- obj
Object
- bytes
Array
: Byte array representing the whole command
- bytes
CommandApdu.toBuffer()
Converts the command to a Buffer
- Returns
Buffer
CommandApdu.toString()
Converts the command to a hex string
- Returns
String
CommandApdu.toByteArray()
Converts the command to a byte array
- Returns
Array
CommandApdu.setLe(le)
Updates the le value of the command
- le
Number
: The new le value
Class: ResponseApdu
Class representing a response from the card
Methods
The ResponseApdu
class has the following methods.
ResponseApdu.meaning()
Interprets the return code and attempts to provide a text translation.
- Returns
String
ResponseApdu.getDataOnly()
Returns the response data without including the status code
- Returns
String
ResponseApdu.getStatusCode()
Returns only the status code
- Returns
String
ResponseApdu.isOk()
Check if the status code is 9000
- Returns
Boolean
ResponseApdu.buffer()
Returns the whole buffer, status code and data
- Returns
Buffer
ResponseApdu.hasMoreBytesAvailable()
Reads the status code and looks for a 61 as sw1, meaning more data is available
- Returns
Boolean
ResponseApdu.numberOfBytesAvailable()
Reads sw2 staus code to return number of bytes left, when sw1 is 61. A value of 0 means there are more than 256 bytes remaining.
- Returns
Number
ResponseApdu.isWrongLength()
Checks status code for 6c as sw1
- Returns
Boolean
ResponseApdu.correctLength()
If sw1 is 6c, returns the correct length from sw2. A value of 0 means there are more than 256 bytes remaining.
- Returns
Number
Class: Iso7816Application
An object offering general commands to most ISO7816 compliant smart cards.
Methods
Constructor Iso7816Application(card)
Sets up the Iso7816Application
object
- card
Card
: The card to communicate with using ISO7816 standards
Iso7816Application.issueCommand(commandApdu)
Sends the provided command to the card. Automatically retrieve the full response, even if it requires multiple GET_RESPONSE commands
- commandApdu
CommandApdu
: Command to send to the card
Returns
ResponseApdu
Complete response from card
Iso7816Application.selectFile(bytes, p1, p2)
Sends the SELECT command to the card, often called selecting an application
- bytes
Buffer
: The resource locater (AID, etc) - p1
Number
: Value to specify as the p1 value - p2
Number
: Value to specify as the p2 value
Returns
ResponseApdu
Complete response from card
Iso7816Application.getResponse(length)
Sends a single GET_RESPONSE command to the card
- length
Number
: The length of the response expected, maximum is 0xFF
Returns
ResponseApdu
Complete response from card
Iso7816Application.getResponse(sfi,record)
Sends a READ_RECORD command to the card
- sfi
Number
: The sfi - record
Number
: The record
Returns
ResponseApdu
Complete response from card
Iso7816Application.getData(p1, p2)
Sends a GET_DATA command to the card
- p1
Number
: Value to specify as the p1 value - p2
Number
: Value to specify as the p2 value
Returns
ResponseApdu
Complete response from card
Events
The Iso7816Application
class emits the following events
Event: 'application-selected'
Emitted when a successful reply to a selectFile()
command is received.
Returns Object
:
- application
String
Examples
With event emitter
'use strict';
const smartcard = require('@paddek/smartcard');
const Devices = smartcard.Devices;
const devices = new Devices();
devices.on('device-activated', (event => {
console.log(`Device '${event.device}' activated`);
event.devices.map((device, index) => {
console.log(`Device #${index + 1}: '${device.name}'`);
});
}));
Selecting the Payment Systems Environment on an EMV (Chip & Pin) card
'use strict';
const smartcard = require('@paddek/smartcard');
const Devices = smartcard.Devices;
const Iso7816Application = smartcard.Iso7816Application;
const devices = new Devices();
devices.on('device-activated', event => {
const currentDevices = event.devices;
let device = event.device;
console.log(`Device '${device}' activated, devices: ${currentDevices}`);
for (let prop in currentDevices) {
console.log("Devices: " + currentDevices[prop]);
}
device.on('card-inserted', event => {
let card = event.card;
console.log(`Card '${card.getAtr()}' inserted into '${event.device}'`);
card.on('command-issued', event => {
console.log(`Command '${event.command}' issued to '${event.card}' `);
});
card.on('response-received', event => {
console.log(`Response '${event.response}' received from '${event.card}' in response to '${event.command}'`);
});
const application = new Iso7816Application(card);
application.selectFile([0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31])
.then(response => {
console.info(`Select PSE Response: '${response}' '${response.meaning()}'`);
}).catch(error => {
console.error('Error:', error, error.stack);
});
});
device.on('card-removed', event => {
console.log(`Card removed from '${event.name}' `);
});
});
devices.on('device-deactivated', event => {
console.log(`Device '${event.device}' deactivated, devices: [${event.devices}]`);
});