Last active
January 8, 2025 12:49
-
-
Save bouroo/ca8a41ac876f713fa8c64cb37c7b36a9 to your computer and use it in GitHub Desktop.
Thai National ID Card reader in NodeJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
/* | |
* Thai National ID Card reader in NodeJS | |
* | |
* @author Kawin Viriyaprasopsook <kawin.vir@zercle.tech> | |
* @requires smartcard legacy-encoding hex2imagebase64 | |
* @since 11/06/2019 | |
* | |
*/ | |
const smartcard = require('smartcard'); | |
const legacy = require('legacy-encoding'); | |
const hex2imagebase64 = require('hex2imagebase64'); | |
const Devices = smartcard.Devices; | |
let devices; | |
try { | |
devices = new Devices(); | |
} catch (err) { | |
console.error(err); | |
process.exit(); | |
} | |
let card; | |
const cmdReq = [0x00, 0xC0, 0x00, 0x00]; | |
const commands = { | |
cmdSelectThaiCard: [0x00, 0xa4, 0x04, 0x00, 0x08, 0xa0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01], | |
cmdCID: [0x80, 0xb0, 0x00, 0x04, 0x02, 0x00, 0x0d], | |
cmdTHFullname: [0x80, 0xb0, 0x00, 0x11, 0x02, 0x00, 0x64], | |
cmdENFullname: [0x80, 0xb0, 0x00, 0x75, 0x02, 0x00, 0x64], | |
cmdBirth: [0x80, 0xb0, 0x00, 0xd9, 0x02, 0x00, 0x08], | |
cmdGender: [0x80, 0xb0, 0x00, 0xe1, 0x02, 0x00, 0x01], | |
cmdIssuer: [0x80, 0xb0, 0x00, 0xf6, 0x02, 0x00, 0x64], | |
cmdIssueDate: [0x80, 0xb0, 0x01, 0x67, 0x02, 0x00, 0x08], | |
cmdExpireDate: [0x80, 0xb0, 0x01, 0x6f, 0x02, 0x00, 0x08], | |
cmdAddress: [0x80, 0xb0, 0x15, 0x79, 0x02, 0x00, 0x64], | |
cmdPhoto: Array.from({ length: 15 }, (_, i) => [0x80, 0xb0, i + 0x01, 0x7b - i, 0x02, 0x00, 0xff]) | |
}; | |
devices.on('device-activated', event => { | |
const { device, devices: currentDevices } = event; | |
console.log(`Device '${device}' activated, devices: ${currentDevices}`); | |
device.on('card-inserted', async (event) => { | |
card = event.card; | |
console.log(`Card '${card.getAtr()}' inserted into '${event.device}'`); | |
// Check Thai National ID Card Version | |
const cardAttr = card.getAtr(); | |
let localCmdReq = cardAttr.startsWith('3b67') ? [0x00, 0xC0, 0x00, 0x01] : cmdReq; | |
try { | |
await card.issueCommand(commands.cmdSelectThaiCard); | |
await fetchAndLogData(commands.cmdCID, localCmdReq, "Get CID: "); | |
await fetchAndLogData(commands.cmdTHFullname, localCmdReq, "Get thFullname: "); | |
await fetchAndLogData(commands.cmdENFullname, localCmdReq, "Get cmdENFullname: "); | |
await fetchAndLogData(commands.cmdBirth, localCmdReq, "Get dateOfBirth: "); | |
await fetchAndLogData(commands.cmdGender, localCmdReq, "Get gender: "); | |
await fetchAndLogData(commands.cmdIssuer, localCmdReq, "Get issuer: "); | |
await fetchAndLogData(commands.cmdIssueDate, localCmdReq, "Get issueDate: "); | |
await fetchAndLogData(commands.cmdExpireDate, localCmdReq, "Get expireDate: "); | |
await fetchAndLogData(commands.cmdAddress, localCmdReq, "Get address: "); | |
await getPhoto(); | |
console.log('Done'); | |
} catch (err) { | |
console.error(err); | |
process.exit(); | |
} | |
}); | |
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}'`); | |
}); | |
async function fetchAndLogData(cmd, req, message) { | |
const data = await getData(cmd, req); | |
console.log(message); | |
console.log(legacy.decode(data.slice(0, -2), 'iso-8859-11')); | |
} | |
async function getPhoto() { | |
let hexPhoto = ''; | |
for (const cmd of commands.cmdPhoto) { | |
const result = await getData(cmd, cmdReq); | |
hexPhoto += result.toString('hex').slice(0, -4); | |
} | |
console.log('Get photo: '); | |
console.log('data:image/jpg;base64, ' + hex2imagebase64(hexPhoto)); | |
} | |
function getData(cmd, req = cmdReq) { | |
return card.issueCommand(cmd).then(() => | |
card.issueCommand([...req, ...cmd.slice(-1)]) | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment