@kodeglot/node-python-eid-reader
v1.0.1
Published
A cross-platform Node.js package to read Belgian eID card public data using Python eidreader with automatic dependency checking
Downloads
11
Maintainers
Readme
Belgian eID Reader
A cross-platform Node.js package to read Belgian eID card public data using Python eidreader with automatic dependency checking. Perfect for Electron apps and Node.js applications.
Features
- 🔍 Cross-platform support: macOS, Windows, and Linux
- 🐍 Python integration: Uses the reliable eidreader Python package
- 🔧 Automatic setup: Checks and installs missing dependencies
- 🛡️ Error handling: Comprehensive error handling with specific error codes
- ⚡ Configurable: Customizable retry logic and paths
- 📦 npm package: Easy to install and use in any Node.js project
- 🖥️ Electron ready: Works seamlessly in Electron applications
- 🔄 Real-time detection: Instant PC/SC reader and card insertion/removal detection
- 📡 Event-driven: Listen for reader and card events in real-time
- 🎯 Dual API: Both traditional eID reading and modern PC/SC detection
Installation
npm install @kodeglot/node-python-eid-readerPrerequisites
Before using this package, you need to install:
- Python 3.x - Download from python.org
- Belgian eID middleware - Download from Belgian government
- eidreader Python package - Will be installed automatically
Quick Start
Basic Usage
import { readEidData } from '@kodeglot/node-python-eid-reader';
try {
const eidData = await readEidData();
console.log('Card holder:', eidData.firstName, eidData.name);
console.log('Card number:', eidData.cardNumber);
} catch (error) {
console.error('Failed to read eID:', error.message);
}Advanced Usage with Options
import { EidReader } from '@kodeglot/node-python-eid-reader';
const reader = new EidReader({
verbose: true, // Enable detailed logging
maxRetries: 5, // Custom retry attempts
retryDelay: 500, // Custom retry delay (ms)
pythonPath: '/usr/bin/python3', // Custom Python path
pkcs11LibPath: '/custom/path/libbeidpkcs11.dylib' // Custom PKCS#11 library
});
try {
const eidData = await reader.readEidData();
console.log('Success:', eidData);
} catch (error) {
console.error('Error:', error.message, error.code);
}Requirements Management
import { checkRequirements, installRequirements } from '@kodeglot/node-python-eid-reader';
// Check if all requirements are met
const result = await checkRequirements();
// NOTE: In Electron/Node.js integration, check result.data.passed, not result.passed
if (result.data && result.data.passed) {
console.log('All requirements are met!');
} else {
console.log('Missing requirements:', result.data?.results);
// Attempt to install missing requirements
const installResult = await installRequirements();
if (installResult.success) {
if (installResult.data && installResult.data.installed) {
console.log('Requirements installed successfully!');
} else {
console.log('All requirements are already available!');
}
} else {
console.log('Failed to install requirements:', installResult.info);
if (installResult.error) {
console.log('Error:', installResult.error.message);
}
}
}API Reference
Real-Time PC/SC Detection (New!)
The package now includes real-time smart card reader and card detection using the cross-platform PC/SC subsystem. This provides instant detection of reader insertion/removal and card insertion/removal events.
Quick Start - Real-Time Detection
import { createPcscDetector } from '@kodeglot/node-python-eid-reader';
// Create a detector for real-time monitoring
const detector = await createPcscDetector();
// Listen for reader events
detector.on('reader-connected', (reader) => {
console.log('Reader connected:', reader.name);
});
detector.on('reader-removed', (reader) => {
console.log('Reader removed:', reader.name);
});
// Listen for card events
detector.on('card-inserted', (reader) => {
console.log('Card inserted in:', reader.name);
});
detector.on('card-removed', (reader) => {
console.log('Card removed from:', reader.name);
});
// Get current status
const status = detector.getStatus();
console.log('Current readers:', status.readers);
// Clean up when done
detector.close();Convenience Functions
import {
isPcscReaderAvailable,
isPcscCardInserted,
getPcscStatus
} from '@kodeglot/node-python-eid-reader';
// Check if any reader is available
const readerResult = await isPcscReaderAvailable();
if (readerResult.success && readerResult.data?.available) {
console.log('PC/SC reader is available');
}
// Check if any card is inserted
const cardResult = await isPcscCardInserted();
if (cardResult.success && cardResult.data?.inserted) {
console.log('Card is inserted in:', cardResult.data.readerName);
}
// Get detailed status
const statusResult = await getPcscStatus();
if (statusResult.success) {
console.log('All readers:', statusResult.data?.readers);
}PcscDetector Class
The main class for real-time PC/SC monitoring.
import { PcscDetector } from '@kodeglot/node-python-eid-reader';
const detector = new PcscDetector();
// Events
detector.on('reader-connected', (reader: PcscReaderStatus) => {
// Reader was connected
});
detector.on('reader-removed', (reader: PcscReaderStatus) => {
// Reader was removed
});
detector.on('card-inserted', (reader: { name: string }) => {
// Card was inserted
});
detector.on('card-removed', (reader: { name: string }) => {
// Card was removed
});
// Methods
const status = detector.getStatus(); // Get current status
detector.close(); // Clean up resourcesTypes
interface PcscReaderStatus {
name: string; // Reader name/identifier
cardPresent: boolean; // Whether a card is currently inserted
}
interface PcscStatus {
readers: PcscReaderStatus[]; // List of all connected readers
}Traditional eID Reading API
readEidData(options?)
Convenience function to read eID data with default options.
Parameters:
options(optional):EidReaderOptions- Configuration options
Returns: Promise<EidData> - The eID card data
EidReader Class
Main class for reading eID data with full control over options.
Constructor
new EidReader(options?: EidReaderOptions)Options:
verbose?: boolean- Enable verbose logging (default: false)maxRetries?: number- Maximum retry attempts (default: 3)retryDelay?: number- Delay between retries in ms (default: 300)pythonPath?: string- Custom Python interpreter pathpkcs11LibPath?: string- Custom PKCS#11 library path
Methods
readEidData(): Promise<EidData>- Read eID data from the cardcheckRequirements(): Promise<{passed: boolean, results: any}>- Check if requirements are metinstallRequirements(): Promise<ReaderResult<{installed: boolean}>>- Install missing requirements
EidData Interface
interface EidData {
cardNumber: string; // Card number (unique identifier)
chipNumber: string; // Chip number
validityDateBegin: string; // Card validity start date
validityDateEnd: string; // Card validity end date
municipality: string; // Issuing municipality
nationality: string; // Nationality
birthLocation: string; // Birth location
birthDate: string; // Birth date
name: string; // Last name
firstName: string; // First name(s)
sex: string; // Gender
documentType: string; // Document type
address: {
streetAndNumber: string; // Street and number
zip: string; // ZIP code
municipality: string; // Municipality
};
photo: string; // Base64 encoded photo
}EidReaderError Class
Custom error class with error codes for better error handling.
Error Codes:
REQUIREMENTS_NOT_MET- Missing dependenciesPYTHON_NOT_FOUND- Python interpreter not foundEIDREADER_FAILED- Python eidreader script failedSPAWN_ERROR- Failed to start Python processMAX_RETRIES_EXCEEDED- Max retry attempts exceededINVALID_OUTPUT- Invalid output from eidreaderPARSE_ERROR- Failed to parse eID data
Electron Integration
This package works seamlessly in Electron applications with built-in enable/disable functionality and real-time PC/SC detection. Here's an example:
Real-Time Detection in Electron
// main.js (Electron main process)
import { createPcscDetector } from '@kodeglot/node-python-eid-reader';
let pcscDetector = null;
let eidReaderEnabled = true;
// Initialize PC/SC detection
async function initializePcscDetection() {
if (eidReaderEnabled) {
pcscDetector = await createPcscDetector();
pcscDetector.on('reader-connected', (reader) => {
mainWindow.webContents.send('reader-state-changed', {
readerAvailable: true,
cardInserted: false,
cardInfo: null
});
});
pcscDetector.on('reader-removed', () => {
mainWindow.webContents.send('reader-state-changed', {
readerAvailable: false,
cardInserted: false,
cardInfo: null
});
});
pcscDetector.on('card-inserted', (reader) => {
mainWindow.webContents.send('reader-state-changed', {
readerAvailable: true,
cardInserted: true,
cardInfo: null
});
});
pcscDetector.on('card-removed', () => {
mainWindow.webContents.send('reader-state-changed', {
readerAvailable: true,
cardInserted: false,
cardInfo: null
});
});
}
}
// Handle enable/disable eID reader
ipcMain.handle('set-eid-enabled', async (event, enabled) => {
eidReaderEnabled = enabled;
if (enabled) {
await initializePcscDetection();
} else {
if (pcscDetector) {
pcscDetector.close();
pcscDetector = null;
}
}
return { success: true, enabled: eidReaderEnabled };
});
// Get current PC/SC status
ipcMain.handle('get-pcsc-status', async () => {
if (!pcscDetector) {
return { success: false, error: 'PC/SC detector not initialized' };
}
const status = pcscDetector.getStatus();
const readerAvailable = status.readers.length > 0;
const cardInserted = status.readers.some(reader => reader.cardPresent);
return {
success: true,
data: {
readerAvailable,
cardInserted,
readers: status.readers
}
};
});// renderer.js (Electron renderer process)
const { ipcRenderer } = require('electron');
// Listen for real-time reader/card state changes
ipcRenderer.on('reader-state-changed', (event, data) => {
console.log('Reader state changed:', data);
updateUI(data.readerAvailable, data.cardInserted);
});
// Get initial status
async function getInitialStatus() {
try {
const result = await ipcRenderer.invoke('get-pcsc-status');
if (result.success) {
updateUI(result.data.readerAvailable, result.data.cardInserted);
}
} catch (error) {
console.error('Failed to get PC/SC status:', error);
}
}
function updateUI(readerAvailable, cardInserted) {
// Update your UI based on reader and card status
document.getElementById('reader-status').textContent =
readerAvailable ? 'Available' : 'Not Available';
document.getElementById('card-status').textContent =
cardInserted ? 'Inserted' : 'Not Inserted';
}Traditional eID Reading in Electron
This package works seamlessly in Electron applications with built-in enable/disable functionality. Here's an example:
// main.js (Electron main process)
import { readEidData } from '@kodeglot/node-python-eid-reader';
let eidReaderEnabled = true; // Default to enabled
// Handle eID reading with enable/disable check
ipcMain.handle('read-eid', async (event) => {
if (!eidReaderEnabled) {
return { success: false, error: 'eID reader is disabled', code: 'DISABLED' };
}
try {
const eidData = await readEidData({ verbose: true });
return { success: true, data: eidData };
} catch (error) {
return { success: false, error: error.message, code: error.code };
}
});
// Handle enable/disable eID reader
ipcMain.handle('set-eid-enabled', async (event, enabled) => {
eidReaderEnabled = enabled;
return { success: true, enabled: eidReaderEnabled };
});
// Handle get eID reader status
ipcMain.handle('get-eid-status', async () => {
return { success: true, enabled: eidReaderEnabled };
});// renderer.js (Electron renderer process)
const { ipcRenderer } = require('electron');
async function readEID() {
try {
const result = await ipcRenderer.invoke('read-eid');
if (result.success) {
console.log('eID data:', result.data);
} else if (result.code === 'DISABLED') {
console.log('eID reader is disabled');
} else {
console.error('Failed:', result.error);
}
} catch (error) {
console.error('IPC error:', error);
}
}
async function toggleEidReader(enabled) {
try {
const result = await ipcRenderer.invoke('set-eid-enabled', enabled);
if (result.success) {
console.log(`eID reader ${enabled ? 'enabled' : 'disabled'}`);
}
} catch (error) {
console.error('Toggle error:', error);
}
}
async function getEidStatus() {
try {
const result = await ipcRenderer.invoke('get-eid-status');
if (result.success) {
console.log(`eID reader is ${result.enabled ? 'enabled' : 'disabled'}`);
}
} catch (error) {
console.error('Status error:', error);
}
}Enable/Disable Features
The Electron integration includes:
- Toggle Switch: Visual toggle to enable/disable the eID reader
- Status Indicator: Shows current enabled/disabled state
- Automatic Blocking: Reading operations are blocked when disabled
- State Persistence: Status is maintained during the app session
- Error Handling: Proper error codes for disabled state
Robust Requirements Check in Electron UI
- The requirements check result is an object with a
dataproperty. - To check if all requirements are met, use
result.data.passedin your UI code. - Example:
if (result.success) {
if (result.data && result.data.passed) {
// All requirements are met
} else {
// Some requirements are missing
}
}- This ensures your UI accurately reflects the backend requirements check result.
Improved Requirements Installation
The installRequirements() function now provides better feedback:
- All requirements available: Returns success with "All requirements are already available!"
- Requirements installed: Returns success with "Requirements installed successfully!"
- Installation failed: Returns failure with detailed info and error messages
Example handling in your UI:
const result = await installRequirements();
if (result.success) {
if (result.data && result.data.installed) {
console.log('Requirements installed successfully!');
} else {
console.log('All requirements are already available!');
}
} else {
console.log('Failed to install requirements:', result.info);
if (result.error) {
console.log('Error:', result.error.message);
}
}Examples
The package includes TypeScript examples demonstrating different usage patterns:
Node.js Example
npm run example:nodeElectron Example
npm run example:electronThe examples are written in TypeScript and show:
- Basic usage with the convenience function
- Advanced usage with the
EidReaderclass - Error handling and requirements management
- Electron integration with IPC handlers
Troubleshooting
Common Issues
"Python not found"
- Ensure Python 3.x is installed and in your PATH
- Use the
pythonPathoption to specify a custom Python path
"eidreader not found"
- The package will attempt to install it automatically
- Manual installation:
pip install eidreader
"Middleware not properly installed"
- Install Belgian eID middleware from eid.belgium.be
- On macOS, ensure the middleware is in
/Library/Belgium Identity Card/ - On Windows, ensure the middleware is in
C:\Program Files\Belgium Identity Card\orC:\Program Files (x86)\Belgium Identity Card\
"Device error"
- Ensure the eID card is properly inserted
- Try removing and reinserting the card
- Check if the card reader is working
"Permission denied"
- On macOS/Linux, you may need to run with sudo for middleware access
- The package will prompt for password when needed
Debug Mode
Enable verbose logging to see detailed information:
const reader = new EidReader({ verbose: true });
const eidData = await reader.readEidData();Environment Variables
You can set these environment variables to customize behavior:
PYKCS11LIB- Path to PKCS#11 libraryDYLD_LIBRARY_PATH- Library path (macOS)PYTHONPATH- Python module search path
Platform-Specific Notes
macOS
- Middleware typically installed in
/Library/Belgium Identity Card/ - May require sudo for first-time access
- DYLD_LIBRARY_PATH is automatically configured
Windows
- Middleware typically installed in
C:\Program Files\Belgium Identity Card\ - Ensure the middleware is properly registered
- May require running as administrator
Linux
- Middleware typically installed in
/usr/lib/ - May need to install additional packages:
sudo apt-get install libbeidpkcs11-0
Development
# Clone the repository
git clone https://github.com/Kodeglot/Node-Python-EID-Reader.git
cd Node-Python-EID-Reader
# Install dependencies
npm install
# Build the package
npm run build
# Run tests
npm start
# Check requirements
npm run check
# Run examples
npm run example:node
npm run example:electronLicense
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
If you encounter any issues:
- Check the troubleshooting section
- Search existing issues
- Create a new issue with detailed information about your problem
Changelog
1.0.0
- Initial release
- Cross-platform support
- Automatic dependency checking
- Electron integration
- Comprehensive error handling
