//Get required packages const electron = require('electron'); const path = require('path'); const url = require('url'); const fs = require('fs'); const asn1js = require('asn1js'); const util = require('util'); const notifier = require('node-notifier'); const smartcard = require('smartcard'); const axios = require('axios') let class_code = ""; let counter = 0; const { app, BrowserWindow, Menu, ipcMain } = electron; let mainWindow; let AddWindow; //Listen for the app to be ready app.on('ready', function () { //Create new window mainWindow = new BrowserWindow({ width: 500, height: 600, webPreferences: { nodeIntegration: true }}); //Load html into window mainWindow.loadURL(url.format({ pathname: path.join(__dirname, "classcode.html"), protocol: "file:", slashes: true })); //Quit app when closed mainWindow.on("closed", function () { app.quit(); }) //Menu from template const mainMenu = Menu.buildFromTemplate(mainMenuTemplate); Menu.setApplicationMenu(mainMenu); }); function readNewCard(application) { application.issueCommand([0x00, 0xA4, 0x04, 0x04, 0x07, 0xD6, 0x16, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); application.issueCommand([0x00, 0xA4, 0x02, 0x04, 0x02, 0x00, 0x02, 0x00]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); var response2 = `${response}`; if(response2.indexOf("6a82") == 0) { console.log("ALERTTTTTT"); readNewCard(application); return; } application.issueCommand([0x00, 0xB0, 0x00, 0x00, 0xE6]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); var response2 = `${response}`; if(response2.indexOf("000000") == 0) { console.log("ALERTTTTTT"); readNewCard(application); return; } var start = response2.indexOf("2a8468016504010101"); start = start + 18; response2 = response2.substring(start); while (1) { var type = response2.substring(0, 2); if (type == "30") break; if (parseInt(response2.substring(2, 4), 16) > 127) { var count = parseInt(response2.substring(2, 4), 16) - 128; var length = ""; var k = 1; for (k = 1; k <= count; k++) { length += response2.substring(2 + (k * 2), 4 + (k * 2)); } var total_length = parseInt(length, 16) * 2; response2 = response2.substr(4 + (k - 1) * 2, total_length); } else { var total_length = parseInt(response2.substring(2, 4), 16) * 2 + 4; response2 = response2.substr(4, total_length); } } //region How to work with ASN.1 strings let bmp_string_encoded = new ArrayBuffer(response2.length / 2); let bmp_string_view = new Uint8Array(bmp_string_encoded); var kk = 0; for (var i = 0; i < (response2.length / 2); i++) { bmp_string_view[i] = "0x" + response2.substring(kk, kk + 2); kk += 2; } let bmp_string_decoded = asn1js.fromBER(bmp_string_encoded); if (bmp_string_decoded.offset === (-1)) return; // Error during decoding let obj = bmp_string_decoded.result.valueBlock.value; var names = obj[4].valueBlock.value[0].valueBlock.value; var surnames = obj[3].valueBlock.value[0].valueBlock.value; var index = obj[5].valueBlock.value; var output = [names, surnames, index]; printStudent(output); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); } function readOldCard(application) { application.selectFile([0xD6, 0x16, 0x00, 0x00, 0x30, 0x01, 0x01]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); application.issueCommand([0x00, 0xA4, 0x02, 0x00, 0x02, 0x00, 0x02, 0x12]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); application.issueCommand([0x00, 0xB0, 0x00, 0x00, 0xF8]) .then(response => { console.info(`Response: '${response}' '${response.meaning()}'`); var response2 = `${response}`; var start = response2.indexOf("2a8468016504010101"); start = start + 18; response2 = response2.substring(start); while (1) { var type = response2.substring(0, 2); if (type == "30") break; if (parseInt(response2.substring(2, 4), 16) > 127) { var count = parseInt(response2.substring(2, 4), 16) - 128; var length = ""; var k = 1; for (k = 1; k <= count; k++) { length += response2.substring(2 + (k * 2), 4 + (k * 2)); } var total_length = parseInt(length, 16) * 2; response2 = response2.substr(4 + (k - 1) * 2, total_length); } else { var total_length = parseInt(response2.substring(2, 4), 16) * 2 + 4; response2 = response2.substr(4, total_length); } } //region How to work with ASN.1 strings let bmp_string_encoded = new ArrayBuffer(response2.length / 2); let bmp_string_view = new Uint8Array(bmp_string_encoded); var kk = 0; for (var i = 0; i < (response2.length / 2); i++) { bmp_string_view[i] = "0x" + response2.substring(kk, kk + 2); kk += 2; } let bmp_string_decoded = asn1js.fromBER(bmp_string_encoded); if (bmp_string_decoded.offset === (-1)) return; // Error during decoding let obj = bmp_string_decoded.result.valueBlock.value; var names = obj[4].valueBlock.value[0].valueBlock.value; var surnames = obj[3].valueBlock.value[0].valueBlock.value; var index = obj[5].valueBlock.value; var output = [names, surnames, index]; printStudent(output); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); }).catch(error => { console.error('Error:', error, error.stack + '\n'); }); } var Devices = smartcard.Devices; var devices = new Devices(); devices.on('device-activated', event => { console.log('Smart card reader active'); var device = event.device; device.on('card-inserted', event => { var card = event.card; //console.log(`Card '${card.getAtr()}' inserted into '${event.device}'` + '\n'); var Iso7816Application = smartcard.Iso7816Application; var application = new Iso7816Application(card); console.log(card.getAtr()); if(card.getAtr() == "3bdd18008131fe4580f9a000000077010800079000fe") { readNewCard(application); } else { readOldCard(application); } }); }); //Add student manually function createAddWindow() { //Create new window AddWindow = new BrowserWindow({ width: 300, height: 400, title: "Add student manually" }); //Load html into window AddWindow.loadURL(url.format({ pathname: path.join(__dirname, "addstudent.html"), protocol: "file:", slashes: true })); //Garbage AddWindow.on("close", function () { AddWindow = null; }); } function printStudent(item) { var dateTime = require('node-datetime'); var dt = dateTime.create(); var formatted = dt.format('d-m-Y H:M:S'); item.push(formatted); mainWindow.webContents.send("item:add", item); notifier.notify({ title: "Student registered", message: item[0] + " " + item[1], icon: path.join(__dirname, 'ok.png') }); axios.post('http://127.0.0.1:8889', JSON.stringify({ classes_code: class_code, student_index: item[2], student_name: item[0], student_surname: item[1] })) .then((res) => { console.log(`statusCode: ${res.statusCode}`) console.log(res) }) .catch((error) => { console.error(error) }) } //Catch ipcMain.on("item:add", function (e, item) { printStudent(item); AddWindow.close(); }) ipcMain.on("card:read", function (e) { card_read(); }) ipcMain.on("set:classcode", function (e,classcode) { class_code = classcode; mainWindow.loadURL(url.format({ pathname: path.join(__dirname, "index.html"), protocol: "file:", slashes: true })); }) //Menu template const mainMenuTemplate = [{ label: "Student", submenu: [{ label: "Add student", accelerator: process.platfrom == "darwin" ? "Command+E" : "Ctrl+E", click() { createAddWindow(); } }, { label: "Quit program", accelerator: process.platfrom == "darwin" ? "Command+Q" : "Ctrl+Q", click() { app.quit(); } } ] }, { label: "Classes", submenu: [{ label: "Add classes", click() { createAddClassesWindow(); } }, { label: "Pick classes", click() { createSelectClassesWindow(); } } ] }]; //If mac psuh empty obj to Menu if (process.platfrom == "darwin") { mainMenuTemplate.unshift({}); } //Add dev tools on DEV if (process.env.NODE_ENV !== 'production') { mainMenuTemplate.push({ label: "DEV", submenu: [{ label: "Toggle dev tools", accelerator: process.platfrom == "darwin" ? "Command+I" : "Ctrl+I", click(item, focusedWindow) { focusedWindow.toggleDevTools(); } }, { role: "reload" } ] }); }