The toolbox for reading and writing nfc cards. Parse card header, ndef message and records, prepare ndef records for writing...
npm:
npm install nfccard-tool --save
yarn:
yarn add nfccard-tool --save
- Parse a card header and wrap raw and human readable data in a object:
- Locks states
- Capability Container
- Magic number
- Spec version
- Max NDEF length
- Read and write accesses
- NDEF message detection and length
- Parse and prepare a NDEF message of types:
- Text
- Uri
- Android App Record
Quick start examples (with the help of nfc-pcsc)
npm run read-nfcpcsc
npm run write-nfcpcsc
const ndef = require('nfccard-tool');
With the card reader of your choice, read from block 0 until end of block 4. Which means a 20 bytes long read.
Note: before any NDEF parsing or preparing we need to parse the card header first using a read command.
// Starts reading in block 0 for 20 bytes long const cardHeader = await reader.read(0, 20); const tag = nfcCard.parseInfo(cardHeader); console.log('tag info:', JSON.stringify(tag));
Which logs:
tag info: { "headerValues":{ "raw":{ "Lock":{ "LOCK0":0, "LOCK1":0 }, "capabilityContainer":{ "MAGIC_NUMBER":225, "SPEC_VERSION":16, "MAX_NDEF_LENGTH":109, "READ_ACCESS":0, "WRITE_ACCESS":0 }, "NDEFMessageHeader":{ "HAS_NDEF":3, "MESSAGE_LENGTH":86 } }, "string":{ "Lock":{ "LOCK0":"0", "LOCK1":"0" }, "capabilityContainer":{ "MAGIC_NUMBER":"E1", "SPEC_VERSION":"10", "MAX_NDEF_LENGTH":"6D", "READ_ACCESS":"0", "WRITE_ACCESS":"0" }, "NDEFMessageHeader":{ "HAS_NDEF":"3", "MESSAGE_LENGTH":"56" } } }, "parsedHeader":{ "isFormatedAsNDEF":true, "type2SpecVersion":"1.0", "maxNDEFMessageSize":872, "hasReadPermissions":true, "getReadPermissionsType":"HAS_READ_ACCESS", "hasWritePermissions":true, "writePermissionsType":"HAS_WRITE_ACCESS", "hasNDEFMessage":true, "NDEFMessageLength":86, "lengthToReadFromBlock4":88 } }
If card header parsing let us know there might be a NDEF message we can try to parse it:
// There might be a NDEF message and we are able to read the tag if(nfcCard.isFormatedAsNDEF() && nfcCard.hasReadPermissions() && nfcCard.hasNDEFMessage()) { // Read the appropriate length to get the NDEF message as buffer const NDEFRawMessage = await reader.read(4, nfcCard.getNDEFMessageLengthToRead()); // starts reading in block 0 until 6 // Parse the buffer as a NDEF raw message const NDEFMessage = nfcCard.parseNDEF(NDEFRawMessage); console.log('NDEFMessage:', NDEFMessage); } else { console.log('Could not parse anything from this tag: \n The tag is either empty, locked, has a wrong NDEF format or is unreadable.') }
We can use the convenient method prepareBytesToWrite to get the appropriate Buffer we need to write a ndef message.
// 1 - READ HEADER // Starts reading in block 0 until end of block 4 const cardHeader = await reader.read(0, 20); const tag = nfcCard.parseInfo(cardHeader); console.log('tag info:', JSON.stringify(tag)); // 2 - WRITE A NDEF MESSAGE AND ITS RECORDS const message = [ { type: 'text', text: 'I\'m a text message', language: 'en' }, { type: 'uri', uri: 'https://github.com/somq' }, { type: 'aar', packageName: 'https://github.com/somq' }, ] // Prepare the buffer to write on the card const rawDataToWrite = nfcCard.prepareBytesToWrite(message); // Write the buffer on the card starting at block 4 const preparationWrite = await reader.write(4, rawDataToWrite.preparedData); // Success ! if (preparationWrite) { console.log('Data have been written successfully.') }
Which logs:
NDEFMessage: [ { NDEFLibRecord: { LanguageCode: null, text: null, _typeNameFormat: 1, _type: [Array], _id: [], _payload: [Array] }, type: 'text', text: 'I\'m a text message', language: 'en' }, { NDEFLibRecord: { RawUri: [], Uri: '', _typeNameFormat: 1, _type: [Array], _id: [], _payload: [Array], type: 'U' }, type: 'uri', uri: 'https://github.com/somq' }, { NDEFLibRecord: { packageName: '', _typeNameFormat: 4, _type: [Array], _id: [], _payload: [Array], type: 'android.com:pkg' }, type: 'aar', packageName: 'https://github.com/somq' } ]
// Magic number nfcCard.isFormatedAsNDEF(); // Type 2 Tag Specification version, eg. 1.0 nfcCard.getType2SpecVersion(); // Max NDEF size for the current tag nfcCard.getMaxNDEFMessageLength(); // Read locked ? nfcCard.hasReadPermissions(); // Read types: HAS_READ_ACCESS, RFU, PROPRIETARY, UNKNOWN nfcCard.getReadPermissionsType(); // Write locked ? nfcCard.hasWritePermissions(); // Write types: HAS_READ_ACCESS, RFU, PROPRIETARY, UNKNOWN nfcCard.getWritePermissionsType(); // NDEF message flag is present ? nfcCard.hasNDEFMessage(); // NDEF message length on exists on the tag nfcCard.getNDEFMessageLength();
{ "headerValues":{ "raw":{ // Raw buffer values "Lock":{ "LOCK0":0, // Lock 0 status - block 2, byte 2 "LOCK1":0 // Lock 1 status - block 2, byte 3 }, "capabilityContainer":{ "MAGIC_NUMBER":225, // magic number - block 3, byte 0 (CC0) "SPEC_VERSION":16, // type 2 spec version - block 3, byte 1 (CC1) "MAX_NDEF_LENGTH":109, // max ndef message length - block 3, byte 2 (CC2) "READ_ACCESS":0, // read access - block 3, byte 3 (CC3) "WRITE_ACCESS":0 // write access - block 3, byte 3 (CC3) }, "NDEFMessageHeader":{ "HAS_NDEF":3, // NDEF header 0 - block 4, byte 0 "MESSAGE_LENGTH":86 // NDEF header 1 - block 4, byte 1 } }, "string":{ // Hex string values "Lock":{ "LOCK0":"0", "LOCK1":"0" }, "capabilityContainer":{ "MAGIC_NUMBER":"E1", "SPEC_VERSION":"10", "MAX_NDEF_LENGTH":"6D", "READ_ACCESS":"0", "WRITE_ACCESS":"0" }, "NDEFMessageHeader":{ "HAS_NDEF":"3", "MESSAGE_LENGTH":"56" } } }, "parsedHeader":{ "isFormatedAsNDEF":true, // magic number - block 3, byte 0 (CC0) "type2SpecVersion":"1.0", // type 2 spec version - block 3, byte 1 (CC1) "maxNDEFMessageSize":872, // max ndef message length - block 3, byte 2 "hasReadPermissions":true, // read access - block 3, byte 3 (CC3) "getReadPermissionsType":"HAS_READ_ACCESS", "hasWritePermissions":true, // write access - block 3, byte 3 (CC3) "writePermissionsType":"HAS_WRITE_ACCESS", "hasNDEFMessage":true, // NDEF header 0 - block 4, byte 0 "NDEFMessageLength":86, // NDEF header 1 - block 4, byte 1 "lengthToReadFromBlock4":88 // NDEFMessageLength + 2 } }
Only a part of Type 2 tag specification is implemented.
This lib does not support yet:
- Dynamical memory structure
- Lock preparing
- ... some are probably missing
Error: path\node_modules@pokusew\pcsclite\build\Release\ pcsclite.node
npm rebuild
We are natively using ndef-lib for parsing but you could give a try at https://github.com/TapTrack/NdefJS or have a deep look at https://github.com/googlearchive/chrome-nfc
If you are looking for a nfc tag reading library take a look at https://github.com/pokusew/nfc-pcsc
MIT Β© somq