Limieza de codigo antiguo

This commit is contained in:
2026-04-13 11:55:50 +02:00
parent 2f17390405
commit 5047f47192
3 changed files with 106 additions and 289 deletions

View File

@@ -2,11 +2,10 @@ import { app, shell, BrowserWindow, ipcMain } from "electron";
import { join } from "path";
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
import icon from "../../resources/icon.png?asset";
import { NfcService } from "../services/NfcService";
import { labelReqHandler, printReqHandler } from "./handlers";
import { logger } from "./LogService";
import { createConnection } from "net";
import { NfcServiceAlt } from "../services/NfcService-alt";
import { NfcService } from "../services/NfcService";
// 1. Global Error Handling (CRITICAL: As early as possible)
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", () => {
return nfcService ? nfcService.getReaderName() : "OFFLINE";
@@ -55,7 +54,7 @@ function createWindow(): void {
// 2. Initialize NFC AFTER window is ready to show (DEFERRED INIT)
logger.info("Deferred: Initializing NfcService...");
try {
nfcService = new NfcServiceAlt((event) => {
nfcService = new NfcService((event) => {
if (!mainWindow.isDestroyed()) {
mainWindow.webContents.send(`nfc:${event.type}`, event);
}

View File

@@ -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
}
}

View File

@@ -1,7 +1,9 @@
import PCSC, { Tag, Reader, KEYS } from "@tockawa/nfc-pcsc";
import { logger } from "../main/LogService";
import { NFC } from "nfc-pcsc";
// @ts-expect-error: .
function formatHexBuffer(buff: Buffer): string {
console.log("LEN:", buff.length);
const str = (
buff
.toString("hex")
@@ -11,17 +13,76 @@ function formatHexBuffer(buff: Buffer): string {
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 =
| { type: "tag"; uid: string }
| { type: "removed"; uid: string }
| { type: "reader"; name: string }
| { type: "error"; message: string };
// Extract the KEY_TYPE_A constant from the KEYS module, which represents the type A authentication key.
const { KEY_TYPE_A } = KEYS;
// 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 NfcService {
private nfc: PCSC;
private nfc: NFC;
private onEvent?: (event: NfcEvent) => void;
private currentReaderName: string = "OFFLINE";
@@ -29,7 +90,7 @@ export class NfcService {
logger.info("NfcService: Constructor start");
try {
logger.info("NfcService: Creating PCSC instance...");
this.nfc = new PCSC.default();
this.nfc = new NFC(console);
logger.info("NfcService: PCSC instance created.");
} catch (err) {
logger.error("NfcService: Failed to create PCSC instance", err);
@@ -48,7 +109,7 @@ export class NfcService {
logger.info(
"NfcService: Starting initialization and attaching listeners...",
);
this.nfc.on("reader", (reader: Reader) => {
this.nfc.on("reader", (reader) => {
console.log(`Lector detectado: ${reader.name}`);
logger.info(`NFC Reader detected: ${reader.name}`);
reader.aid = "a0000000041010";
@@ -57,25 +118,48 @@ export class NfcService {
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;
};
reader.on("card", async (card: Tag) => {
console.log(`Tarjeta detectada! UID: ${JSON.stringify(card)}`);
logger.info(`NFC Tag detected: ${card.uid}`);
const GET_OPTIONS = "80A8000002830000";
const res = await reader.transmit(
Buffer.from(GET_OPTIONS, "hex"),
18,
logger.info(`NFC Tag detected: ${JSON.stringify(card)}`);
await send(commands.app, "step 1 - select app", 255);
await send(commands.options, "step 2 - read options", 255);
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) {
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}`);
logger.info(`NFC Tag removed: ${card.uid}`);
if (this.onEvent) {