Limieza de codigo antiguo
This commit is contained in:
@@ -2,11 +2,10 @@ import { app, shell, BrowserWindow, ipcMain } from "electron";
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
|
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
|
||||||
import icon from "../../resources/icon.png?asset";
|
import icon from "../../resources/icon.png?asset";
|
||||||
import { NfcService } from "../services/NfcService";
|
|
||||||
import { labelReqHandler, printReqHandler } from "./handlers";
|
import { labelReqHandler, printReqHandler } from "./handlers";
|
||||||
import { logger } from "./LogService";
|
import { logger } from "./LogService";
|
||||||
import { createConnection } from "net";
|
import { createConnection } from "net";
|
||||||
import { NfcServiceAlt } from "../services/NfcService-alt";
|
import { NfcService } from "../services/NfcService";
|
||||||
|
|
||||||
// 1. Global Error Handling (CRITICAL: As early as possible)
|
// 1. Global Error Handling (CRITICAL: As early as possible)
|
||||||
process.on("uncaughtException", (error) => {
|
process.on("uncaughtException", (error) => {
|
||||||
@@ -41,7 +40,7 @@ function createWindow(): void {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let nfcService: NfcServiceAlt | null = null;
|
let nfcService: NfcService | null = null;
|
||||||
|
|
||||||
ipcMain.handle("nfc:getReaderName", () => {
|
ipcMain.handle("nfc:getReaderName", () => {
|
||||||
return nfcService ? nfcService.getReaderName() : "OFFLINE";
|
return nfcService ? nfcService.getReaderName() : "OFFLINE";
|
||||||
@@ -55,7 +54,7 @@ function createWindow(): void {
|
|||||||
// 2. Initialize NFC AFTER window is ready to show (DEFERRED INIT)
|
// 2. Initialize NFC AFTER window is ready to show (DEFERRED INIT)
|
||||||
logger.info("Deferred: Initializing NfcService...");
|
logger.info("Deferred: Initializing NfcService...");
|
||||||
try {
|
try {
|
||||||
nfcService = new NfcServiceAlt((event) => {
|
nfcService = new NfcService((event) => {
|
||||||
if (!mainWindow.isDestroyed()) {
|
if (!mainWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.send(`nfc:${event.type}`, event);
|
mainWindow.webContents.send(`nfc:${event.type}`, event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,266 +0,0 @@
|
|||||||
import { logger } from "../main/LogService";
|
|
||||||
import { NFC } from "nfc-pcsc";
|
|
||||||
|
|
||||||
function formatHexBuffer(buff: Buffer): string {
|
|
||||||
console.log("LEN:", buff.length);
|
|
||||||
const str = (
|
|
||||||
buff
|
|
||||||
.toString("hex")
|
|
||||||
.replace(/(.{2})/g, "$1 ")
|
|
||||||
.match(/.{1,48}/g) ?? [""]
|
|
||||||
).join("\n");
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findIndexOfPattern(buff: Buffer, pattern: number[]): number {
|
|
||||||
if (pattern.length === 0) return -1;
|
|
||||||
|
|
||||||
for (let i = 0; i <= buff.length - pattern.length; i++) {
|
|
||||||
let coincidencia = true;
|
|
||||||
|
|
||||||
for (let j = 0; j < pattern.length; j++) {
|
|
||||||
if (buff[i + j] !== pattern[j]) {
|
|
||||||
coincidencia = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coincidencia) return i; // Retorna el índice de inicio
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1; // Retorna -1 si no encuentra nada
|
|
||||||
}
|
|
||||||
|
|
||||||
function decodeRecord(buff: Buffer): number {
|
|
||||||
// Se suponde que el byte 0 del token es el inicio del PAN
|
|
||||||
// https://www.eftlab.com/knowledge-base/complete-list-of-emv-nfc-tags
|
|
||||||
const effectiveDate = [0x5f, 0x25];
|
|
||||||
const pan = [0x5a];
|
|
||||||
const panseq = [0x5f, 0x34];
|
|
||||||
const usageControl = [0x9f, 0x07];
|
|
||||||
const cdol = [0x8c];
|
|
||||||
// ISO/IEC 7813
|
|
||||||
const issuerData = [0x57];
|
|
||||||
|
|
||||||
if (buff.length < 164) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. byte de inicio del PAN
|
|
||||||
const inicio = findIndexOfPattern(buff, pan);
|
|
||||||
|
|
||||||
if (inicio == undefined) return 1;
|
|
||||||
|
|
||||||
// 2. 38 bytes desde ahi (offset de 2) por la instruccion
|
|
||||||
const inicioPAN = inicio + pan.length;
|
|
||||||
const finPan = inicioPAN + 1 + buff[inicioPAN];
|
|
||||||
const fin = inicioPAN + 38; // 38 es supuestamente la longitud del public token
|
|
||||||
//console.log("IDXPAN", inicioPAN, finPan, buff[inicioPAN]);
|
|
||||||
|
|
||||||
const completePAN = buff.subarray(inicioPAN, finPan);
|
|
||||||
console.log("PAN:\n", formatHexBuffer(completePAN));
|
|
||||||
const complete = buff.subarray(inicioPAN, fin);
|
|
||||||
console.log("CODIGO:\n", formatHexBuffer(complete));
|
|
||||||
|
|
||||||
const inicioIDD = findIndexOfPattern(buff, issuerData);
|
|
||||||
if (inicioIDD == undefined) return 1;
|
|
||||||
const lenIDD = buff[inicioIDD + issuerData.length];
|
|
||||||
const complpeteIDD = buff.subarray(
|
|
||||||
inicioIDD,
|
|
||||||
lenIDD + inicioIDD + issuerData.length + 1,
|
|
||||||
);
|
|
||||||
console.log("INICIOIDD", inicioIDD, lenIDD);
|
|
||||||
console.log("IDD:", formatHexBuffer(complpeteIDD));
|
|
||||||
|
|
||||||
// Inmediatamente despues del PAN tiene el codigo 5f 34 (01) (00) que inica que
|
|
||||||
// solo hay una tarjeta con este PAN pero en la imagen de treezor hay un separador
|
|
||||||
// y la fecha de expiracion.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Para leer el public token:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findPublicToken(buff: Buffer): string {
|
|
||||||
/**
|
|
||||||
57 - EMV
|
|
||||||
13 - LEN (19)
|
|
||||||
[3B] 54 69 23 - PAN BIN
|
|
||||||
[5B] 08 79 39 81 68 - PAN REMANDER
|
|
||||||
|
|
||||||
[4B]
|
|
||||||
d - separador
|
|
||||||
29 09 - fecha de expiración
|
|
||||||
22 1 - codigo de servicio
|
|
||||||
|
|
||||||
[7B]
|
|
||||||
0 - separador
|
|
||||||
00 00 06 1 - public token (7)
|
|
||||||
97 5 - cvc
|
|
||||||
00 - public token (2)
|
|
||||||
f - padding
|
|
||||||
*/
|
|
||||||
const BYTE_INICIO_TOKEN = 12;
|
|
||||||
const issuerData = [0x57];
|
|
||||||
const emvOffset = issuerData.length + 1;
|
|
||||||
const inicio = findIndexOfPattern(buff, issuerData);
|
|
||||||
const finIndex = inicio + emvOffset + buff[inicio + issuerData.length];
|
|
||||||
const issuerDataBuff = buff.subarray(inicio, finIndex);
|
|
||||||
const inicioData = emvOffset; // EMV + LEN
|
|
||||||
const inicioToken = inicioData + BYTE_INICIO_TOKEN;
|
|
||||||
const tokenbuff = issuerDataBuff.subarray(inicioToken);
|
|
||||||
const tokenstr = tokenbuff.toString("hex");
|
|
||||||
// El primer cuarteto es un 0 de separacion el último es una f de padding
|
|
||||||
const token = tokenstr.substring(1, 8) + tokenstr.substring(11, 13);
|
|
||||||
console.log("Public token", tokenstr, " - ", token);
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NfcEvent =
|
|
||||||
| { type: "tag"; uid: string }
|
|
||||||
| { type: "removed"; uid: string }
|
|
||||||
| { type: "reader"; name: string }
|
|
||||||
| { type: "error"; message: string };
|
|
||||||
|
|
||||||
// Estan hardcodeados pero en principio no deberia hacer falta más
|
|
||||||
const commands = {
|
|
||||||
app: [0x00, 0xa4, 0x04, 0x00, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x00],
|
|
||||||
options: [0x80, 0xa8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00],
|
|
||||||
record: [0x00, 0xb2, 0x01, 0x14, 0x00],
|
|
||||||
};
|
|
||||||
/** PROVISIONAL */
|
|
||||||
export class NfcServiceAlt {
|
|
||||||
private nfc: NFC;
|
|
||||||
private onEvent?: (event: NfcEvent) => void;
|
|
||||||
private currentReaderName: string = "OFFLINE";
|
|
||||||
|
|
||||||
constructor(onEvent?: (event: NfcEvent) => void) {
|
|
||||||
logger.info("NfcService: Constructor start");
|
|
||||||
try {
|
|
||||||
logger.info("NfcService: Creating PCSC instance...");
|
|
||||||
this.nfc = new NFC(console);
|
|
||||||
logger.info("NfcService: PCSC instance created.");
|
|
||||||
} catch (err) {
|
|
||||||
logger.error("NfcService: Failed to create PCSC instance", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
this.onEvent = onEvent;
|
|
||||||
this.init();
|
|
||||||
logger.info("NfcService: Constructor end");
|
|
||||||
}
|
|
||||||
|
|
||||||
public getReaderName(): string {
|
|
||||||
return this.currentReaderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private init(): void {
|
|
||||||
logger.info(
|
|
||||||
"NfcService: Starting initialization and attaching listeners...",
|
|
||||||
);
|
|
||||||
this.nfc.on("reader", (reader) => {
|
|
||||||
console.log(`Lector detectado: ${reader.name}`);
|
|
||||||
logger.info(`NFC Reader detected: ${reader.name}`);
|
|
||||||
reader.aid = "a0000000041010";
|
|
||||||
|
|
||||||
this.currentReaderName = reader.name;
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({ type: "reader", name: reader.name });
|
|
||||||
}
|
|
||||||
reader.autoProcessing = false;
|
|
||||||
|
|
||||||
reader.on("card", async (card) => {
|
|
||||||
const send = async (
|
|
||||||
cmd: number[],
|
|
||||||
comment: string | null = null,
|
|
||||||
responseMaxLength: number = 40,
|
|
||||||
): Promise<Buffer<ArrayBufferLike>> => {
|
|
||||||
const b = Buffer.from(cmd);
|
|
||||||
/*
|
|
||||||
console.log(
|
|
||||||
(comment ? `[${comment}] ` : "") + `sending`,
|
|
||||||
b,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
const data = await reader.transmit(b, responseMaxLength);
|
|
||||||
/*
|
|
||||||
console.log(
|
|
||||||
(comment ? `[${comment}] ` : "") + `received data \n`,
|
|
||||||
formatHexBuffer(data),
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`Tarjeta detectada! UID: ${JSON.stringify(card)}`);
|
|
||||||
logger.info(`NFC Tag detected: ${JSON.stringify(card)}`);
|
|
||||||
|
|
||||||
const res1 = await send(
|
|
||||||
commands.app,
|
|
||||||
"step 1 - select app",
|
|
||||||
255,
|
|
||||||
);
|
|
||||||
const res2 = await send(
|
|
||||||
commands.options,
|
|
||||||
"step 2 - read options",
|
|
||||||
255,
|
|
||||||
);
|
|
||||||
const res3 = await send(
|
|
||||||
commands.record,
|
|
||||||
"step 3 - read record 2 - 1",
|
|
||||||
255,
|
|
||||||
);
|
|
||||||
|
|
||||||
//decodeRecord(res3);
|
|
||||||
const token = findPublicToken(res3);
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({ type: "tag", uid: token });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
reader.on("card.off", async (card) => {
|
|
||||||
console.log(`Tarjeta retirada: ${card.uid}`);
|
|
||||||
logger.info(`NFC Tag removed: ${card.uid}`);
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({ type: "removed", uid: card.uid });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
reader.on("error", (err: Error) => {
|
|
||||||
console.error(`Error en el lector ${reader.name}:`, err);
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({
|
|
||||||
type: "error",
|
|
||||||
message: err.message || String(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
reader.on("end", () => {
|
|
||||||
console.log(`Lector desconectado: ${reader.name}`);
|
|
||||||
logger.info(`NFC Reader disconnected: ${reader.name}`);
|
|
||||||
this.currentReaderName = "OFFLINE";
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({ type: "reader", name: "OFFLINE" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.nfc.on("error", (err: Error) => {
|
|
||||||
console.error("Error general de NFC:", err);
|
|
||||||
if (this.onEvent) {
|
|
||||||
this.onEvent({
|
|
||||||
type: "error",
|
|
||||||
message: err.message || String(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
logger.info("NfcService: Initialization sequence complete.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop(): void {
|
|
||||||
// La mayoría de los lectores se cierran solos al cerrar la app
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import PCSC, { Tag, Reader, KEYS } from "@tockawa/nfc-pcsc";
|
|
||||||
import { logger } from "../main/LogService";
|
import { logger } from "../main/LogService";
|
||||||
|
import { NFC } from "nfc-pcsc";
|
||||||
|
|
||||||
|
// @ts-expect-error: .
|
||||||
function formatHexBuffer(buff: Buffer): string {
|
function formatHexBuffer(buff: Buffer): string {
|
||||||
|
console.log("LEN:", buff.length);
|
||||||
const str = (
|
const str = (
|
||||||
buff
|
buff
|
||||||
.toString("hex")
|
.toString("hex")
|
||||||
@@ -11,17 +13,76 @@ function formatHexBuffer(buff: Buffer): string {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findIndexOfPattern(buff: Buffer, pattern: number[]): number {
|
||||||
|
if (pattern.length === 0) return -1;
|
||||||
|
|
||||||
|
for (let i = 0; i <= buff.length - pattern.length; i++) {
|
||||||
|
let coincidencia = true;
|
||||||
|
|
||||||
|
for (let j = 0; j < pattern.length; j++) {
|
||||||
|
if (buff[i + j] !== pattern[j]) {
|
||||||
|
coincidencia = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coincidencia) return i; // Retorna el índice de inicio
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // Retorna -1 si no encuentra nada
|
||||||
|
}
|
||||||
|
|
||||||
|
function findPublicToken(buff: Buffer): string {
|
||||||
|
/**
|
||||||
|
57 - EMV
|
||||||
|
13 - LEN (19)
|
||||||
|
[3B] 54 69 23 - PAN BIN
|
||||||
|
[5B] 08 79 39 81 68 - PAN REMANDER
|
||||||
|
|
||||||
|
[4B]
|
||||||
|
d - separador
|
||||||
|
29 09 - fecha de expiración
|
||||||
|
22 1 - codigo de servicio
|
||||||
|
|
||||||
|
[7B]
|
||||||
|
0 - separador
|
||||||
|
00 00 06 1 - public token (7)
|
||||||
|
97 5 - cvc
|
||||||
|
00 - public token (2)
|
||||||
|
f - padding
|
||||||
|
*/
|
||||||
|
const BYTE_INICIO_TOKEN = 12;
|
||||||
|
const issuerData = [0x57];
|
||||||
|
const emvOffset = issuerData.length + 1;
|
||||||
|
const inicio = findIndexOfPattern(buff, issuerData);
|
||||||
|
const finIndex = inicio + emvOffset + buff[inicio + issuerData.length];
|
||||||
|
const issuerDataBuff = buff.subarray(inicio, finIndex);
|
||||||
|
const inicioData = emvOffset; // EMV + LEN
|
||||||
|
const inicioToken = inicioData + BYTE_INICIO_TOKEN;
|
||||||
|
const tokenbuff = issuerDataBuff.subarray(inicioToken);
|
||||||
|
const tokenstr = tokenbuff.toString("hex");
|
||||||
|
// El primer cuarteto es un 0 de separacion el último es una f de padding
|
||||||
|
const token = tokenstr.substring(1, 8) + tokenstr.substring(11, 13);
|
||||||
|
console.log("Public token", tokenstr, " - ", token);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
export type NfcEvent =
|
export type NfcEvent =
|
||||||
| { type: "tag"; uid: string }
|
| { type: "tag"; uid: string }
|
||||||
| { type: "removed"; uid: string }
|
| { type: "removed"; uid: string }
|
||||||
| { type: "reader"; name: string }
|
| { type: "reader"; name: string }
|
||||||
| { type: "error"; message: string };
|
| { type: "error"; message: string };
|
||||||
|
|
||||||
// Extract the KEY_TYPE_A constant from the KEYS module, which represents the type A authentication key.
|
// Estan hardcodeados pero en principio no deberia hacer falta más
|
||||||
const { KEY_TYPE_A } = KEYS;
|
const commands = {
|
||||||
|
app: [0x00, 0xa4, 0x04, 0x00, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x00],
|
||||||
|
options: [0x80, 0xa8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00],
|
||||||
|
record: [0x00, 0xb2, 0x01, 0x14, 0x00],
|
||||||
|
};
|
||||||
|
/** PROVISIONAL */
|
||||||
export class NfcService {
|
export class NfcService {
|
||||||
private nfc: PCSC;
|
private nfc: NFC;
|
||||||
private onEvent?: (event: NfcEvent) => void;
|
private onEvent?: (event: NfcEvent) => void;
|
||||||
private currentReaderName: string = "OFFLINE";
|
private currentReaderName: string = "OFFLINE";
|
||||||
|
|
||||||
@@ -29,7 +90,7 @@ export class NfcService {
|
|||||||
logger.info("NfcService: Constructor start");
|
logger.info("NfcService: Constructor start");
|
||||||
try {
|
try {
|
||||||
logger.info("NfcService: Creating PCSC instance...");
|
logger.info("NfcService: Creating PCSC instance...");
|
||||||
this.nfc = new PCSC.default();
|
this.nfc = new NFC(console);
|
||||||
logger.info("NfcService: PCSC instance created.");
|
logger.info("NfcService: PCSC instance created.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("NfcService: Failed to create PCSC instance", err);
|
logger.error("NfcService: Failed to create PCSC instance", err);
|
||||||
@@ -48,7 +109,7 @@ export class NfcService {
|
|||||||
logger.info(
|
logger.info(
|
||||||
"NfcService: Starting initialization and attaching listeners...",
|
"NfcService: Starting initialization and attaching listeners...",
|
||||||
);
|
);
|
||||||
this.nfc.on("reader", (reader: Reader) => {
|
this.nfc.on("reader", (reader) => {
|
||||||
console.log(`Lector detectado: ${reader.name}`);
|
console.log(`Lector detectado: ${reader.name}`);
|
||||||
logger.info(`NFC Reader detected: ${reader.name}`);
|
logger.info(`NFC Reader detected: ${reader.name}`);
|
||||||
reader.aid = "a0000000041010";
|
reader.aid = "a0000000041010";
|
||||||
@@ -57,25 +118,48 @@ export class NfcService {
|
|||||||
if (this.onEvent) {
|
if (this.onEvent) {
|
||||||
this.onEvent({ type: "reader", name: reader.name });
|
this.onEvent({ type: "reader", name: reader.name });
|
||||||
}
|
}
|
||||||
|
reader.autoProcessing = false;
|
||||||
|
|
||||||
|
reader.on("card", async (card) => {
|
||||||
|
const send = async (
|
||||||
|
cmd: number[],
|
||||||
|
comment: string | null = null,
|
||||||
|
responseMaxLength: number = 40,
|
||||||
|
): Promise<Buffer<ArrayBufferLike>> => {
|
||||||
|
const b = Buffer.from(cmd);
|
||||||
|
console.log(
|
||||||
|
(comment ? `[${comment}] ` : "") + `sending`,
|
||||||
|
b,
|
||||||
|
);
|
||||||
|
const data = await reader.transmit(b, responseMaxLength);
|
||||||
|
/*
|
||||||
|
console.log(
|
||||||
|
(comment ? `[${comment}] ` : "") + `received data \n`,
|
||||||
|
formatHexBuffer(data),
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
reader.on("card", async (card: Tag) => {
|
|
||||||
console.log(`Tarjeta detectada! UID: ${JSON.stringify(card)}`);
|
console.log(`Tarjeta detectada! UID: ${JSON.stringify(card)}`);
|
||||||
logger.info(`NFC Tag detected: ${card.uid}`);
|
logger.info(`NFC Tag detected: ${JSON.stringify(card)}`);
|
||||||
const GET_OPTIONS = "80A8000002830000";
|
|
||||||
const res = await reader.transmit(
|
await send(commands.app, "step 1 - select app", 255);
|
||||||
Buffer.from(GET_OPTIONS, "hex"),
|
await send(commands.options, "step 2 - read options", 255);
|
||||||
18,
|
const res3 = await send(
|
||||||
|
commands.record,
|
||||||
|
"step 3 - read record 2 - 1",
|
||||||
|
255,
|
||||||
);
|
);
|
||||||
console.log("PORCESSING OPTIONS", res.toString("hex"));
|
|
||||||
|
//decodeRecord(res3);
|
||||||
|
const token = findPublicToken(res3);
|
||||||
if (this.onEvent) {
|
if (this.onEvent) {
|
||||||
this.onEvent({ type: "tag", uid: card.uid });
|
this.onEvent({ type: "tag", uid: token });
|
||||||
}
|
}
|
||||||
//await reader.authenticate(2, KEY_TYPE_A, "A000000004");
|
|
||||||
//const data = await reader.read(2, 16);
|
|
||||||
//console.log("bloque2", data.toString("utf8"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
reader.on("card.off", async (card: Tag) => {
|
reader.on("card.off", async (card) => {
|
||||||
console.log(`Tarjeta retirada: ${card.uid}`);
|
console.log(`Tarjeta retirada: ${card.uid}`);
|
||||||
logger.info(`NFC Tag removed: ${card.uid}`);
|
logger.info(`NFC Tag removed: ${card.uid}`);
|
||||||
if (this.onEvent) {
|
if (this.onEvent) {
|
||||||
|
|||||||
Reference in New Issue
Block a user