235 lines
8.2 KiB
TypeScript
235 lines
8.2 KiB
TypeScript
import {NFC} from "nfc-pcsc";
|
|
import {IPCSend} from "./IPCHandler";
|
|
import {
|
|
IPCListenChannels,
|
|
NFCAccountCard,
|
|
NFCCard,
|
|
NFCCardType,
|
|
NFCPropertyCard,
|
|
NFCTaskCard,
|
|
PropertyColor, TaskType
|
|
} from "./RawConstants";
|
|
import * as fs from "fs";
|
|
import path from "path";
|
|
|
|
|
|
export default class NFCHandler {
|
|
public static initPCSC() {
|
|
const nfc = new NFC(); // optionally you can pass logger
|
|
|
|
nfc.on('reader', reader => {
|
|
|
|
console.log(`${reader.name} device attached`);
|
|
|
|
// enable when you want to auto-process ISO 14443-4 tags (standard=TAG_ISO_14443_4)
|
|
// when an ISO 14443-4 is detected, SELECT FILE command with the AID is issued
|
|
// the response is available as card.data in the card event
|
|
// see examples/basic.js line 17 for more info
|
|
// reader.aid = 'F222222222';
|
|
|
|
reader.on('card', card => {
|
|
// card is object containing following data
|
|
// [always] String type: TAG_ISO_14443_3 (standard nfc tags like MIFARE) or TAG_ISO_14443_4 (Android HCE and others)
|
|
// [always] String standard: same as type
|
|
// [only TAG_ISO_14443_3] String uid: tag uid
|
|
// [only TAG_ISO_14443_4] Buffer data: raw data from select APDU response
|
|
|
|
console.log(`${reader.name} card detected`, card);
|
|
|
|
let parsed = this.formClass(card.uid, card.data.toString("utf8"));
|
|
if (parsed && parsed.isComplete)
|
|
IPCSend(IPCListenChannels.NFC_CARD, {status: true, data: parsed.card});
|
|
|
|
IPCSend(IPCListenChannels.NFC_RAW, {status: !!parsed, data: parsed});
|
|
});
|
|
|
|
reader.on('card.off', card => {
|
|
console.log(`${reader.name} card removed`, card);
|
|
});
|
|
|
|
reader.on('error', err => {
|
|
console.log(`${reader.name} an error occurred`, err);
|
|
});
|
|
|
|
reader.on('end', () => {
|
|
console.log(`${reader.name} device removed`);
|
|
});
|
|
|
|
});
|
|
|
|
nfc.on('error', err => {
|
|
console.log('an error occurred', err);
|
|
});
|
|
}
|
|
|
|
public static initTest() {
|
|
fs.watchFile(path.resolve(process.cwd(), "nfc.test"), (curr, prev) => {
|
|
let contents = fs.readFileSync(path.resolve(process.cwd(), "nfc.test")).toString("utf-8");
|
|
let parsed = this.formClass("xyz", contents);
|
|
if (parsed)
|
|
IPCSend(IPCListenChannels.NFC_CARD, {status: true, data: parsed.card});
|
|
|
|
IPCSend(IPCListenChannels.NFC_RAW, {status: parsed.isComplete, data: parsed.card});
|
|
|
|
console.log("Got NFC", parsed);
|
|
})
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns formed nfc card or null if nothing can be parsed
|
|
* @param uid
|
|
* @param raw
|
|
*/
|
|
public static formClass(uid: string, raw: string): formClassReturn | null {
|
|
/*
|
|
NFC-Card FULL
|
|
|
|
CARD_TYPE|PROPERTIES
|
|
|
|
- ACCOUNT
|
|
- PROPERTY
|
|
- TASK
|
|
*/
|
|
let preParsed: NFCCard = {
|
|
uid: uid,
|
|
raw: raw,
|
|
cardType: NFCCardType.INVALID,
|
|
};
|
|
|
|
try {
|
|
let parsing = raw.split("|");
|
|
switch (parsing[0]) {
|
|
case "PROPERTY": {
|
|
preParsed.cardType = NFCCardType.PROPERTY;
|
|
const splitProperty = parsing[1].split(";");
|
|
/*
|
|
0 Name
|
|
1 Color
|
|
2 Fullset Amount
|
|
3 Buy Value
|
|
4 Mortgage Value
|
|
5 Rent Object (split with ,)
|
|
0 Basic rent
|
|
[1 Rent with 1 house
|
|
2 Rent with 2 houses
|
|
3 Rent with 3 houses
|
|
4 Rent with 4 houses
|
|
5 Rent with 1 hotel]
|
|
6 Special Props
|
|
""
|
|
"TRAINSTATION"
|
|
"UTILITY"
|
|
*/
|
|
let name = this.valueOr(splitProperty, 0, "");
|
|
let color = this.valueOr(splitProperty, 1, PropertyColor.WHITE);
|
|
let fullSetAmount = this.valueOr(splitProperty, 2, 0);
|
|
let buyValue = this.valueOr(splitProperty, 3, 0);
|
|
let mortgageValue = this.valueOr(splitProperty, 4, 0);
|
|
|
|
let rent = 0;
|
|
let rent1 = 0;
|
|
let rent2 = 0;
|
|
let rent3 = 0;
|
|
let rent4 = 0;
|
|
let rentHotel = 0;
|
|
if (splitProperty[5]) {
|
|
let rentSplit = splitProperty[5].split(",");
|
|
rent = this.valueOr(rentSplit, 0, 0);
|
|
rent1 = this.valueOr(rentSplit, 1, undefined);
|
|
rent2 = this.valueOr(rentSplit, 2, undefined);
|
|
rent3 = this.valueOr(rentSplit, 3, undefined);
|
|
rent4 = this.valueOr(rentSplit, 4, undefined);
|
|
rentHotel = this.valueOr(rentSplit, 5, undefined);
|
|
}
|
|
|
|
let specialProperties = this.valueOr(splitProperty, 6, "");
|
|
|
|
let propertyParsed: NFCPropertyCard = {
|
|
...preParsed,
|
|
name: name,
|
|
color: color,
|
|
fullSetAmount: fullSetAmount,
|
|
buyValue: buyValue,
|
|
mortgageValue: mortgageValue,
|
|
rent: rent,
|
|
rent1: rent1,
|
|
rent2: rent2,
|
|
rent3: rent3,
|
|
rent4: rent4,
|
|
rentHotel: rentHotel,
|
|
specialProperties: specialProperties,
|
|
};
|
|
|
|
if (splitProperty.length != 7)
|
|
return {card: propertyParsed, isComplete: false};
|
|
|
|
return {card: propertyParsed, isComplete: true};
|
|
}
|
|
|
|
case "ACCOUNT": {
|
|
preParsed.cardType = NFCCardType.ACCOUNT;
|
|
const splitAccount = parsing[1].split(";");
|
|
let symbol = this.valueOr(splitAccount, 0, "");
|
|
let nickname = this.valueOr(splitAccount, 1, "");
|
|
let pin = this.valueOr(splitAccount, 2, 0);
|
|
|
|
const splitParsed: NFCAccountCard = {
|
|
...preParsed,
|
|
symbol: symbol,
|
|
nickname: nickname,
|
|
pin: Number.parseInt(pin)
|
|
}
|
|
|
|
if (splitAccount.length != 3)
|
|
return {card: splitParsed, isComplete: false};
|
|
return {card: splitParsed, isComplete: true}
|
|
}
|
|
|
|
case "TASK": {
|
|
preParsed.cardType = NFCCardType.ACCOUNT;
|
|
const splitTask = parsing[1].split(";");
|
|
let taskType = this.valueOr(splitTask, 0, "");
|
|
let taskAmount1 = this.valueOr(splitTask, 1, 0);
|
|
let taskAmount2 = this.valueOr(splitTask, 2, 0);
|
|
|
|
const splitParsed: NFCTaskCard = {
|
|
...preParsed,
|
|
type: taskType as TaskType,
|
|
amount: Number.parseInt(taskAmount1) || 0,
|
|
amount2: Number.parseInt(taskAmount2) || 0
|
|
}
|
|
|
|
if (splitTask.length < 1 || splitTask.length > 3)
|
|
return {card: splitParsed, isComplete: false};
|
|
|
|
return {card: splitParsed, isComplete: true}
|
|
}
|
|
|
|
default: {
|
|
return {card: preParsed, isComplete: false};
|
|
}
|
|
|
|
}
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
private static valueOr(arr: string[], index: number, def: any) {
|
|
try {
|
|
if (arr[index])
|
|
return arr[index];
|
|
return def;
|
|
} catch (e) {
|
|
return def;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
interface formClassReturn {
|
|
card: NFCCard;
|
|
isComplete: boolean;
|
|
} |