@ukeyfe/react-native-nfc-litecard 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +239 -7
- package/dist/index.js +1449 -49
- package/package.json +6 -4
- package/dist/constants.d.ts +0 -87
- package/dist/constants.js +0 -117
- package/dist/crypto.d.ts +0 -55
- package/dist/crypto.js +0 -271
- package/dist/nfc-core.d.ts +0 -74
- package/dist/nfc-core.js +0 -375
- package/dist/reader.d.ts +0 -98
- package/dist/reader.js +0 -619
- package/dist/types.d.ts +0 -80
- package/dist/types.js +0 -113
- package/dist/utils.d.ts +0 -43
- package/dist/utils.js +0 -124
- package/dist/writer.d.ts +0 -46
- package/dist/writer.js +0 -623
package/dist/reader.js
DELETED
|
@@ -1,619 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* NFC Reader Module
|
|
4
|
-
*
|
|
5
|
-
* Public API:
|
|
6
|
-
* - checkCard() – detect whether a card is empty or contains data
|
|
7
|
-
* - readMnemonic() – read mnemonic (password required)
|
|
8
|
-
* - readUserNickname() – read user nickname (password optional)
|
|
9
|
-
* - readMnemonicRetryCount() – read the PIN retry counter
|
|
10
|
-
* - resetRetryCountTo10() – reset the retry counter to default
|
|
11
|
-
* - cardInfoToJson() – serialise card-info to JSON
|
|
12
|
-
*
|
|
13
|
-
* Based on MIFARE Ultralight AES (MF0AES(H)20) datasheet.
|
|
14
|
-
*/
|
|
15
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
-
if (k2 === undefined) k2 = k;
|
|
17
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
-
}
|
|
21
|
-
Object.defineProperty(o, k2, desc);
|
|
22
|
-
}) : (function(o, m, k, k2) {
|
|
23
|
-
if (k2 === undefined) k2 = k;
|
|
24
|
-
o[k2] = m[k];
|
|
25
|
-
}));
|
|
26
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
-
}) : function(o, v) {
|
|
29
|
-
o["default"] = v;
|
|
30
|
-
});
|
|
31
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
-
var ownKeys = function(o) {
|
|
33
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
-
var ar = [];
|
|
35
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
-
return ar;
|
|
37
|
-
};
|
|
38
|
-
return ownKeys(o);
|
|
39
|
-
};
|
|
40
|
-
return function (mod) {
|
|
41
|
-
if (mod && mod.__esModule) return mod;
|
|
42
|
-
var result = {};
|
|
43
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
-
__setModuleDefault(result, mod);
|
|
45
|
-
return result;
|
|
46
|
-
};
|
|
47
|
-
})();
|
|
48
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
-
exports.DEFAULT_PIN_RETRY_COUNT = exports.clearNfcOperationCancelledByCleanup = exports.getNfcOperationCancelledByCleanupTimestamp = exports.consumeNfcOperationCancelledByCleanup = exports.markNfcOperationCancelledByCleanup = exports.releaseNfcOperationLock = exports.isNfcOperationLocked = exports.NfcStatusCode = void 0;
|
|
50
|
-
exports.cardInfoToJson = cardInfoToJson;
|
|
51
|
-
exports.checkCard = checkCard;
|
|
52
|
-
exports.readMnemonic = readMnemonic;
|
|
53
|
-
exports.readUserNickname = readUserNickname;
|
|
54
|
-
exports.readMnemonicRetryCount = readMnemonicRetryCount;
|
|
55
|
-
exports.resetRetryCountTo10 = resetRetryCountTo10;
|
|
56
|
-
exports.getCardVersion = getCardVersion;
|
|
57
|
-
exports.readOriginality = readOriginality;
|
|
58
|
-
const bip39 = __importStar(require("bip39"));
|
|
59
|
-
const constants_1 = require("./constants");
|
|
60
|
-
Object.defineProperty(exports, "DEFAULT_PIN_RETRY_COUNT", { enumerable: true, get: function () { return constants_1.DEFAULT_PIN_RETRY_COUNT; } });
|
|
61
|
-
const types_1 = require("./types");
|
|
62
|
-
Object.defineProperty(exports, "NfcStatusCode", { enumerable: true, get: function () { return types_1.NfcStatusCode; } });
|
|
63
|
-
const utils_1 = require("./utils");
|
|
64
|
-
const crypto_1 = require("./crypto");
|
|
65
|
-
const nfc_core_1 = require("./nfc-core");
|
|
66
|
-
Object.defineProperty(exports, "isNfcOperationLocked", { enumerable: true, get: function () { return
|
|
67
|
-
// re-export lock helpers so consumers can manage lock from outside
|
|
68
|
-
nfc_core_1.isNfcOperationLocked; } });
|
|
69
|
-
Object.defineProperty(exports, "releaseNfcOperationLock", { enumerable: true, get: function () { return nfc_core_1.releaseNfcOperationLock; } });
|
|
70
|
-
Object.defineProperty(exports, "markNfcOperationCancelledByCleanup", { enumerable: true, get: function () { return nfc_core_1.markNfcOperationCancelledByCleanup; } });
|
|
71
|
-
Object.defineProperty(exports, "consumeNfcOperationCancelledByCleanup", { enumerable: true, get: function () { return nfc_core_1.consumeNfcOperationCancelledByCleanup; } });
|
|
72
|
-
Object.defineProperty(exports, "getNfcOperationCancelledByCleanupTimestamp", { enumerable: true, get: function () { return nfc_core_1.getNfcOperationCancelledByCleanupTimestamp; } });
|
|
73
|
-
Object.defineProperty(exports, "clearNfcOperationCancelledByCleanup", { enumerable: true, get: function () { return nfc_core_1.clearNfcOperationCancelledByCleanup; } });
|
|
74
|
-
// ===========================================================================
|
|
75
|
-
// Internal read helpers
|
|
76
|
-
// ===========================================================================
|
|
77
|
-
/** FAST_READ pages 0x04–0x07 (card info area). */
|
|
78
|
-
async function readUserCardInfo() {
|
|
79
|
-
const response = await (0, nfc_core_1.transceive)([constants_1.CMD_FAST_READ, constants_1.USER_CARD_INFO_PAGE_START, constants_1.USER_CARD_INFO_PAGE_END]);
|
|
80
|
-
if (!response || response.length < constants_1.USER_CARD_INFO_SIZE)
|
|
81
|
-
throw new Error('READ_FAILED');
|
|
82
|
-
return new Uint8Array(response.slice(0, constants_1.USER_CARD_INFO_SIZE));
|
|
83
|
-
}
|
|
84
|
-
/** FAST_READ nickname pages (last 3 pages of user memory). */
|
|
85
|
-
async function readUserNicknameInternal() {
|
|
86
|
-
const response = await (0, nfc_core_1.transceive)([constants_1.CMD_FAST_READ, constants_1.USER_NICKNAME_PAGE_START, constants_1.USER_NICKNAME_PAGE_END]);
|
|
87
|
-
if (!response || response.length < constants_1.USER_NICKNAME_MAX_LENGTH)
|
|
88
|
-
throw new Error('READ_FAILED');
|
|
89
|
-
const responseArray = Array.isArray(response) ? response : Array.from(response);
|
|
90
|
-
const nicknameBytes = new Uint8Array(responseArray.slice(0, constants_1.USER_NICKNAME_MAX_LENGTH));
|
|
91
|
-
// Find actual length (ignore trailing 0x00 padding)
|
|
92
|
-
let actualLength = 0;
|
|
93
|
-
for (let i = 0; i < constants_1.USER_NICKNAME_MAX_LENGTH; i++) {
|
|
94
|
-
if (nicknameBytes[i] !== 0x00)
|
|
95
|
-
actualLength = i + 1;
|
|
96
|
-
}
|
|
97
|
-
if (actualLength === 0)
|
|
98
|
-
return '';
|
|
99
|
-
try {
|
|
100
|
-
return new TextDecoder('utf-8').decode(nicknameBytes.slice(0, actualLength));
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// Fallback: ASCII-compatible manual conversion
|
|
104
|
-
let result = '';
|
|
105
|
-
for (let i = 0; i < actualLength; i++)
|
|
106
|
-
result += String.fromCharCode(nicknameBytes[i]);
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// ===========================================================================
|
|
111
|
-
// Entropy → mnemonic conversion
|
|
112
|
-
// ===========================================================================
|
|
113
|
-
/**
|
|
114
|
-
* Decode on-card data into a BIP-39 mnemonic.
|
|
115
|
-
*
|
|
116
|
-
* Data layout: [type 1B] [entropy 16-32B] [CRC16 2B]
|
|
117
|
-
*/
|
|
118
|
-
function entropyToMnemonic(data) {
|
|
119
|
-
if (data.length < 19)
|
|
120
|
-
throw new Error('INVALID_CARD_DATA');
|
|
121
|
-
if (data.every(b => b === 0))
|
|
122
|
-
throw new Error('EMPTY_CARD');
|
|
123
|
-
const { entropyLength, description } = (0, utils_1.getMnemonicTypeInfo)(data[0]);
|
|
124
|
-
const expectedTotal = 1 + entropyLength + 2;
|
|
125
|
-
if (data.length < expectedTotal)
|
|
126
|
-
throw new Error('INVALID_CARD_DATA');
|
|
127
|
-
const dataBlock = data.slice(0, 1 + entropyLength);
|
|
128
|
-
const storedCRC = (0, utils_1.extractCRC16)(data.slice(1 + entropyLength, expectedTotal));
|
|
129
|
-
const calcCRC = (0, utils_1.calculateCRC16)(dataBlock);
|
|
130
|
-
if (storedCRC !== calcCRC)
|
|
131
|
-
throw new Error('CRC16_CHECK_FAILED');
|
|
132
|
-
const entropyBytes = data.slice(1, 1 + entropyLength);
|
|
133
|
-
const entropyHex = (0, utils_1.bytesToHex)(Array.from(entropyBytes));
|
|
134
|
-
const rawBytes = (0, utils_1.bytesToHex)(Array.from(dataBlock));
|
|
135
|
-
const mnemonic = bip39.entropyToMnemonic(entropyHex);
|
|
136
|
-
return { mnemonic, entropyHex, type: description, rawBytes, crc16: calcCRC };
|
|
137
|
-
}
|
|
138
|
-
// ===========================================================================
|
|
139
|
-
// Card info parsing
|
|
140
|
-
// ===========================================================================
|
|
141
|
-
const CARD_TYPE_MAP = {
|
|
142
|
-
0x00: 'Unknown',
|
|
143
|
-
0x01: 'Standard',
|
|
144
|
-
0x02: 'Encrypted',
|
|
145
|
-
0x10: 'Test',
|
|
146
|
-
0x14: 'UKey',
|
|
147
|
-
0x20: 'Development',
|
|
148
|
-
};
|
|
149
|
-
function parseCardInfo(data) {
|
|
150
|
-
if (!data || data.length < constants_1.USER_CARD_INFO_SIZE)
|
|
151
|
-
throw new Error('INVALID_CARD_DATA');
|
|
152
|
-
const version = data[0];
|
|
153
|
-
const cardType = data[1];
|
|
154
|
-
const infoBytes = data.slice(2, constants_1.USER_CARD_INFO_SIZE);
|
|
155
|
-
const rawBytes = (0, utils_1.bytesToHex)(Array.from(data.slice(0, constants_1.USER_CARD_INFO_SIZE)));
|
|
156
|
-
const pageBreakdown = [];
|
|
157
|
-
for (let i = 0; i < Math.ceil(constants_1.USER_CARD_INFO_SIZE / constants_1.PAGE_SIZE); i++) {
|
|
158
|
-
const off = i * constants_1.PAGE_SIZE;
|
|
159
|
-
const pageBytes = Array.from(data.slice(off, off + constants_1.PAGE_SIZE));
|
|
160
|
-
pageBreakdown.push({
|
|
161
|
-
page: constants_1.USER_CARD_INFO_PAGE_START + i,
|
|
162
|
-
bytes: pageBytes,
|
|
163
|
-
hex: (0, utils_1.bytesToHex)(pageBytes),
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
version,
|
|
168
|
-
cardType,
|
|
169
|
-
rawBytes,
|
|
170
|
-
infoBytes,
|
|
171
|
-
json: {
|
|
172
|
-
pageInfo: {
|
|
173
|
-
startPage: constants_1.USER_CARD_INFO_PAGE_START,
|
|
174
|
-
endPage: constants_1.USER_CARD_INFO_PAGE_END,
|
|
175
|
-
totalPages: Math.ceil(constants_1.USER_CARD_INFO_SIZE / constants_1.PAGE_SIZE),
|
|
176
|
-
totalBytes: constants_1.USER_CARD_INFO_SIZE,
|
|
177
|
-
},
|
|
178
|
-
version: { value: version, hex: `0x${version.toString(16).padStart(2, '0')}` },
|
|
179
|
-
cardType: {
|
|
180
|
-
value: cardType,
|
|
181
|
-
hex: `0x${cardType.toString(16).padStart(2, '0')}`,
|
|
182
|
-
description: CARD_TYPE_MAP[cardType] || `Unknown (0x${cardType.toString(16).padStart(2, '0')})`,
|
|
183
|
-
known: cardType in CARD_TYPE_MAP,
|
|
184
|
-
},
|
|
185
|
-
additionalInfo: { hex: (0, utils_1.bytesToHex)(Array.from(infoBytes)), bytes: Array.from(infoBytes) },
|
|
186
|
-
rawData: { hex: rawBytes, bytes: Array.from(data.slice(0, constants_1.USER_CARD_INFO_SIZE)), length: constants_1.USER_CARD_INFO_SIZE },
|
|
187
|
-
pageBreakdown,
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
/** Serialise parseCardInfo result to JSON. */
|
|
192
|
-
function cardInfoToJson(cardInfo, pretty = true) {
|
|
193
|
-
return pretty ? JSON.stringify(cardInfo.json, null, 2) : JSON.stringify(cardInfo.json);
|
|
194
|
-
}
|
|
195
|
-
// ===========================================================================
|
|
196
|
-
// Public API
|
|
197
|
-
// ===========================================================================
|
|
198
|
-
/**
|
|
199
|
-
* Detect whether the card is empty or already contains data.
|
|
200
|
-
*
|
|
201
|
-
* Without password: tries to read without auth.
|
|
202
|
-
* - Read succeeds & first byte is a valid mnemonic type → HAS_DATA
|
|
203
|
-
* - Read succeeds & first byte is other → EMPTY
|
|
204
|
-
* - Read fails (auth required) → HAS_DATA (read-protection is on, cannot determine)
|
|
205
|
-
*
|
|
206
|
-
* With password: authenticates first, then reads and validates with CRC16.
|
|
207
|
-
* - Valid mnemonic payload → HAS_DATA (with type info)
|
|
208
|
-
* - Empty or invalid data → EMPTY
|
|
209
|
-
* - Auth failure → AUTH_WRONG_PASSWORD
|
|
210
|
-
*/
|
|
211
|
-
async function checkCard(password, onCardIdentified) {
|
|
212
|
-
try {
|
|
213
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
217
|
-
}
|
|
218
|
-
try {
|
|
219
|
-
try {
|
|
220
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
221
|
-
}
|
|
222
|
-
catch {
|
|
223
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
224
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
225
|
-
}
|
|
226
|
-
try {
|
|
227
|
-
if (password) {
|
|
228
|
-
// Authenticated check: decrement retry → authenticate → read → validate CRC16
|
|
229
|
-
try {
|
|
230
|
-
await (0, nfc_core_1.decrementRetryCountInSession)();
|
|
231
|
-
}
|
|
232
|
-
catch (error) {
|
|
233
|
-
const code = (0, types_1.errorToCode)(error);
|
|
234
|
-
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
235
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
236
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
237
|
-
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const aesKey = (0, crypto_1.passwordToAesKey)(password);
|
|
241
|
-
await (0, nfc_core_1.authenticate)(aesKey);
|
|
242
|
-
// Auth succeeded – reset retry counter
|
|
243
|
-
try {
|
|
244
|
-
await (0, nfc_core_1.writeRetryCountInSession)(constants_1.DEFAULT_PIN_RETRY_COUNT);
|
|
245
|
-
}
|
|
246
|
-
catch { /* non-fatal */ }
|
|
247
|
-
onCardIdentified?.();
|
|
248
|
-
const data = await (0, nfc_core_1.readUserMemory)();
|
|
249
|
-
try {
|
|
250
|
-
const decoded = (0, utils_1.validateMnemonicPayload)(data);
|
|
251
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
252
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
253
|
-
return { code: types_1.NfcStatusCode.CHECK_HAS_DATA, success: true, data: { type: decoded.type } };
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
257
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
258
|
-
return { code: types_1.NfcStatusCode.CHECK_EMPTY, success: true };
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
// Unauthenticated check: try to read first page directly
|
|
263
|
-
onCardIdentified?.();
|
|
264
|
-
let response = null;
|
|
265
|
-
try {
|
|
266
|
-
response = await (0, nfc_core_1.transceive)([constants_1.CMD_READ, constants_1.USER_PAGE_START]);
|
|
267
|
-
}
|
|
268
|
-
catch { /* read-protected */ }
|
|
269
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
270
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
271
|
-
if (response && response.length >= 4) {
|
|
272
|
-
let hasData = false;
|
|
273
|
-
try {
|
|
274
|
-
(0, utils_1.getMnemonicTypeInfo)(response[0]);
|
|
275
|
-
hasData = true;
|
|
276
|
-
}
|
|
277
|
-
catch { /* not a valid type */ }
|
|
278
|
-
return { code: hasData ? types_1.NfcStatusCode.CHECK_HAS_DATA : types_1.NfcStatusCode.CHECK_EMPTY, success: true };
|
|
279
|
-
}
|
|
280
|
-
// Read failed = protection is on, assume has data
|
|
281
|
-
return { code: types_1.NfcStatusCode.CHECK_HAS_DATA, success: true };
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
catch (error) {
|
|
285
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
286
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
287
|
-
const code = (0, types_1.errorToCode)(error);
|
|
288
|
-
return { code, success: false };
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
catch (error) {
|
|
292
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
293
|
-
throw error;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Read the mnemonic from a password-protected card.
|
|
298
|
-
*
|
|
299
|
-
* Flow: connect → pre-decrement retry counter → authenticate → read →
|
|
300
|
-
* decode entropy → read nickname → reset retry counter → release
|
|
301
|
-
*/
|
|
302
|
-
async function readMnemonic(password, onCardIdentified) {
|
|
303
|
-
try {
|
|
304
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
308
|
-
}
|
|
309
|
-
let retryCountAfterPreDecrement;
|
|
310
|
-
try {
|
|
311
|
-
try {
|
|
312
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
316
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
// Pre-decrement retry counter before auth attempt
|
|
320
|
-
try {
|
|
321
|
-
const next = await (0, nfc_core_1.decrementRetryCountInSession)();
|
|
322
|
-
if (typeof next === 'number')
|
|
323
|
-
retryCountAfterPreDecrement = next;
|
|
324
|
-
}
|
|
325
|
-
catch (error) {
|
|
326
|
-
const code = (0, types_1.errorToCode)(error);
|
|
327
|
-
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
328
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
329
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
330
|
-
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
const aesKey = (0, crypto_1.passwordToAesKey)(password);
|
|
334
|
-
await (0, nfc_core_1.authenticate)(aesKey);
|
|
335
|
-
onCardIdentified?.();
|
|
336
|
-
const data = await (0, nfc_core_1.readUserMemory)();
|
|
337
|
-
const result = entropyToMnemonic(data);
|
|
338
|
-
let nickname;
|
|
339
|
-
try {
|
|
340
|
-
nickname = await readUserNicknameInternal();
|
|
341
|
-
}
|
|
342
|
-
catch { /* non-fatal */ }
|
|
343
|
-
// Auth succeeded – reset counter to default
|
|
344
|
-
let finalRetryCount;
|
|
345
|
-
try {
|
|
346
|
-
await (0, nfc_core_1.writeRetryCountInSession)(constants_1.DEFAULT_PIN_RETRY_COUNT);
|
|
347
|
-
finalRetryCount = constants_1.DEFAULT_PIN_RETRY_COUNT;
|
|
348
|
-
}
|
|
349
|
-
catch { /* non-fatal */ }
|
|
350
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
351
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
352
|
-
return {
|
|
353
|
-
code: types_1.NfcStatusCode.READ_SUCCESS,
|
|
354
|
-
success: true,
|
|
355
|
-
data: {
|
|
356
|
-
mnemonic: result.mnemonic,
|
|
357
|
-
type: result.type,
|
|
358
|
-
entropyHex: result.entropyHex,
|
|
359
|
-
rawBytes: result.rawBytes,
|
|
360
|
-
nickname,
|
|
361
|
-
retryCount: finalRetryCount,
|
|
362
|
-
},
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
const isTimeout = error?.message?.includes('TRANSCEIVE_TIMEOUT') ||
|
|
367
|
-
error?.message?.includes('timeout') ||
|
|
368
|
-
error?.message?.includes('TagLost');
|
|
369
|
-
await (0, nfc_core_1.releaseNfcTech)(isTimeout);
|
|
370
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
371
|
-
const code = (0, types_1.errorToCode)(error);
|
|
372
|
-
return {
|
|
373
|
-
code,
|
|
374
|
-
success: false,
|
|
375
|
-
data: typeof retryCountAfterPreDecrement === 'number' ? { retryCount: retryCountAfterPreDecrement } : undefined,
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
381
|
-
throw error;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Read the user nickname from the card.
|
|
386
|
-
* @param password – supply if the card has read-protection enabled.
|
|
387
|
-
*/
|
|
388
|
-
async function readUserNickname(password, onCardIdentified) {
|
|
389
|
-
try {
|
|
390
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
391
|
-
}
|
|
392
|
-
catch {
|
|
393
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
394
|
-
}
|
|
395
|
-
try {
|
|
396
|
-
try {
|
|
397
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
398
|
-
}
|
|
399
|
-
catch {
|
|
400
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
401
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
402
|
-
}
|
|
403
|
-
try {
|
|
404
|
-
if (password) {
|
|
405
|
-
const aesKey = (0, crypto_1.passwordToAesKey)(password);
|
|
406
|
-
await (0, nfc_core_1.authenticate)(aesKey);
|
|
407
|
-
}
|
|
408
|
-
onCardIdentified?.();
|
|
409
|
-
const nickname = await readUserNicknameInternal();
|
|
410
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
411
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
412
|
-
return {
|
|
413
|
-
code: types_1.NfcStatusCode.READ_NICKNAME_SUCCESS,
|
|
414
|
-
success: true,
|
|
415
|
-
data: { nickname },
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
catch (error) {
|
|
419
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
420
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
421
|
-
const code = (0, types_1.errorToCode)(error);
|
|
422
|
-
return { code, success: false };
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
catch (error) {
|
|
426
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
427
|
-
throw error;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
/** Read the current PIN retry counter from the card. */
|
|
431
|
-
async function readMnemonicRetryCount(onCardIdentified) {
|
|
432
|
-
try {
|
|
433
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
434
|
-
}
|
|
435
|
-
catch {
|
|
436
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
437
|
-
}
|
|
438
|
-
try {
|
|
439
|
-
try {
|
|
440
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
441
|
-
}
|
|
442
|
-
catch {
|
|
443
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
444
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
445
|
-
}
|
|
446
|
-
try {
|
|
447
|
-
onCardIdentified?.();
|
|
448
|
-
const pageBlock = await (0, nfc_core_1.transceive)([constants_1.CMD_READ, constants_1.RETRY_COUNTER_PAGE]);
|
|
449
|
-
if (!pageBlock || pageBlock.length < constants_1.PAGE_SIZE) {
|
|
450
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
451
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
452
|
-
return {
|
|
453
|
-
code: types_1.NfcStatusCode.READ_RETRY_COUNT_SUCCESS,
|
|
454
|
-
success: true,
|
|
455
|
-
data: { retryCount: 0 },
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
const retryCount = typeof pageBlock[constants_1.RETRY_COUNTER_OFFSET] === 'number' ? pageBlock[constants_1.RETRY_COUNTER_OFFSET] & 0xff : 0;
|
|
459
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
460
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
461
|
-
return {
|
|
462
|
-
code: types_1.NfcStatusCode.READ_RETRY_COUNT_SUCCESS,
|
|
463
|
-
success: true,
|
|
464
|
-
data: { retryCount },
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
catch (error) {
|
|
468
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
469
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
470
|
-
const code = (0, types_1.errorToCode)(error);
|
|
471
|
-
return { code, success: false };
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
catch (error) {
|
|
475
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
476
|
-
throw error;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
/** Reset the PIN retry counter to the default value (10). */
|
|
480
|
-
async function resetRetryCountTo10(onCardIdentified) {
|
|
481
|
-
try {
|
|
482
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
483
|
-
}
|
|
484
|
-
catch {
|
|
485
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
486
|
-
}
|
|
487
|
-
try {
|
|
488
|
-
try {
|
|
489
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
490
|
-
}
|
|
491
|
-
catch {
|
|
492
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
493
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
494
|
-
}
|
|
495
|
-
try {
|
|
496
|
-
onCardIdentified?.();
|
|
497
|
-
await (0, nfc_core_1.writeRetryCountInSession)(constants_1.DEFAULT_PIN_RETRY_COUNT);
|
|
498
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
499
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
500
|
-
return {
|
|
501
|
-
code: types_1.NfcStatusCode.READ_RETRY_COUNT_SUCCESS,
|
|
502
|
-
success: true,
|
|
503
|
-
data: { retryCount: constants_1.DEFAULT_PIN_RETRY_COUNT },
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
catch (error) {
|
|
507
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
508
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
509
|
-
const code = (0, types_1.errorToCode)(error);
|
|
510
|
-
return { code, success: false };
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
catch (error) {
|
|
514
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
515
|
-
throw error;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Read card product version info (GET_VERSION command).
|
|
520
|
-
* No authentication required.
|
|
521
|
-
*/
|
|
522
|
-
async function getCardVersion(onCardIdentified) {
|
|
523
|
-
try {
|
|
524
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
525
|
-
}
|
|
526
|
-
catch {
|
|
527
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
528
|
-
}
|
|
529
|
-
try {
|
|
530
|
-
try {
|
|
531
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
532
|
-
}
|
|
533
|
-
catch {
|
|
534
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
535
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
536
|
-
}
|
|
537
|
-
try {
|
|
538
|
-
onCardIdentified?.();
|
|
539
|
-
const response = await (0, nfc_core_1.transceive)([constants_1.CMD_GET_VERSION]);
|
|
540
|
-
if (!response || response.length < 8) {
|
|
541
|
-
throw new Error('READ_FAILED');
|
|
542
|
-
}
|
|
543
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
544
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
545
|
-
return {
|
|
546
|
-
code: types_1.NfcStatusCode.GET_VERSION_SUCCESS,
|
|
547
|
-
success: true,
|
|
548
|
-
data: {
|
|
549
|
-
version: {
|
|
550
|
-
vendorId: response[1],
|
|
551
|
-
productType: response[2],
|
|
552
|
-
productSubtype: response[3],
|
|
553
|
-
majorVersion: response[4],
|
|
554
|
-
minorVersion: response[5],
|
|
555
|
-
storageSize: response[6],
|
|
556
|
-
protocolType: response[7],
|
|
557
|
-
},
|
|
558
|
-
},
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
catch (error) {
|
|
562
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
563
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
564
|
-
const code = (0, types_1.errorToCode)(error);
|
|
565
|
-
return { code, success: false };
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
catch (error) {
|
|
569
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
570
|
-
throw error;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Read the ECC originality signature (READ_SIG command).
|
|
575
|
-
* Verifies the card is a genuine NXP product.
|
|
576
|
-
* No authentication required (unless Random ID is enabled).
|
|
577
|
-
*/
|
|
578
|
-
async function readOriginality(onCardIdentified) {
|
|
579
|
-
try {
|
|
580
|
-
await (0, nfc_core_1.acquireNfcLock)();
|
|
581
|
-
}
|
|
582
|
-
catch {
|
|
583
|
-
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
584
|
-
}
|
|
585
|
-
try {
|
|
586
|
-
try {
|
|
587
|
-
await (0, nfc_core_1.requestNfcTech)();
|
|
588
|
-
}
|
|
589
|
-
catch {
|
|
590
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
591
|
-
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
592
|
-
}
|
|
593
|
-
try {
|
|
594
|
-
onCardIdentified?.();
|
|
595
|
-
const response = await (0, nfc_core_1.transceive)([constants_1.CMD_READ_SIG, 0x00]);
|
|
596
|
-
if (!response || response.length < 48) {
|
|
597
|
-
throw new Error('READ_FAILED');
|
|
598
|
-
}
|
|
599
|
-
const signatureHex = (0, utils_1.bytesToHex)(response.slice(0, 48));
|
|
600
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
601
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
602
|
-
return {
|
|
603
|
-
code: types_1.NfcStatusCode.READ_SIG_SUCCESS,
|
|
604
|
-
success: true,
|
|
605
|
-
data: { signature: signatureHex },
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
catch (error) {
|
|
609
|
-
await (0, nfc_core_1.releaseNfcTech)();
|
|
610
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
611
|
-
const code = (0, types_1.errorToCode)(error);
|
|
612
|
-
return { code, success: false };
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
catch (error) {
|
|
616
|
-
(0, nfc_core_1.releaseNfcLock)();
|
|
617
|
-
throw error;
|
|
618
|
-
}
|
|
619
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unified result codes, NfcResult interface, and error mapping helpers.
|
|
3
|
-
*
|
|
4
|
-
* All codes are unique across reader and writer to prevent ambiguity.
|
|
5
|
-
* - Reader success : 101xx
|
|
6
|
-
* - Writer success : 102xx
|
|
7
|
-
* - Failure : 4xxxx (shared)
|
|
8
|
-
*
|
|
9
|
-
* This library does NOT provide user-facing messages.
|
|
10
|
-
* The caller should map NfcStatusCode to their own localised strings.
|
|
11
|
-
*/
|
|
12
|
-
export declare const NfcStatusCode: {
|
|
13
|
-
readonly READ_SUCCESS: 10102;
|
|
14
|
-
readonly READ_NICKNAME_SUCCESS: 10103;
|
|
15
|
-
readonly CHECK_EMPTY: 10104;
|
|
16
|
-
readonly CHECK_HAS_DATA: 10105;
|
|
17
|
-
readonly READ_RETRY_COUNT_SUCCESS: 10106;
|
|
18
|
-
readonly GET_VERSION_SUCCESS: 10107;
|
|
19
|
-
readonly READ_SIG_SUCCESS: 10108;
|
|
20
|
-
readonly INIT_SUCCESS: 10201;
|
|
21
|
-
readonly WRITE_SUCCESS: 10203;
|
|
22
|
-
readonly UPDATE_PASSWORD_SUCCESS: 10204;
|
|
23
|
-
readonly WRITE_NICKNAME_SUCCESS: 10205;
|
|
24
|
-
readonly RESET_SUCCESS: 10206;
|
|
25
|
-
/** Card already has a valid mnemonic backup; write was skipped */
|
|
26
|
-
readonly PRECHECK_HAS_BACKUP: 10207;
|
|
27
|
-
readonly NFC_CONNECT_FAILED: 40001;
|
|
28
|
-
readonly AUTH_WRONG_PASSWORD: 40002;
|
|
29
|
-
readonly AUTH_INVALID_RESPONSE: 40003;
|
|
30
|
-
readonly AUTH_VERIFY_FAILED: 40004;
|
|
31
|
-
readonly READ_FAILED: 40005;
|
|
32
|
-
readonly WRITE_FAILED: 40006;
|
|
33
|
-
readonly INVALID_MNEMONIC: 40007;
|
|
34
|
-
readonly UNSUPPORTED_MNEMONIC_LENGTH: 40008;
|
|
35
|
-
readonly INVALID_CARD_DATA: 40009;
|
|
36
|
-
readonly UNKNOWN_ERROR: 40010;
|
|
37
|
-
readonly NFC_USER_CANCELED: 40011;
|
|
38
|
-
readonly READ_TIMEOUT: 40012;
|
|
39
|
-
readonly NFC_LOCK_TIMEOUT: 40013;
|
|
40
|
-
readonly CRC16_CHECK_FAILED: 40014;
|
|
41
|
-
/** PIN retry counter is 0; no authentication attempts left */
|
|
42
|
-
readonly RETRY_COUNT_EXHAUSTED: 40015;
|
|
43
|
-
};
|
|
44
|
-
export interface NfcResult {
|
|
45
|
-
/** Numeric result code – compare against NfcStatusCode constants */
|
|
46
|
-
code: number;
|
|
47
|
-
/** Whether the operation succeeded */
|
|
48
|
-
success: boolean;
|
|
49
|
-
/** Returned data (optional, only present for some operations) */
|
|
50
|
-
data?: {
|
|
51
|
-
mnemonic?: string;
|
|
52
|
-
type?: string;
|
|
53
|
-
entropyHex?: string;
|
|
54
|
-
rawBytes?: string;
|
|
55
|
-
nickname?: string;
|
|
56
|
-
retryCount?: number;
|
|
57
|
-
aesKeyHex?: string;
|
|
58
|
-
crc16?: number;
|
|
59
|
-
version?: {
|
|
60
|
-
vendorId: number;
|
|
61
|
-
productType: number;
|
|
62
|
-
productSubtype: number;
|
|
63
|
-
majorVersion: number;
|
|
64
|
-
minorVersion: number;
|
|
65
|
-
storageSize: number;
|
|
66
|
-
protocolType: number;
|
|
67
|
-
};
|
|
68
|
-
signature?: string;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Unified failure result when the PIN retry counter has reached 0.
|
|
73
|
-
* Used by readMnemonic, updateCard, updatePassword, and resetCard.
|
|
74
|
-
*/
|
|
75
|
-
export declare function nfcResultRetryCountExhausted(): NfcResult;
|
|
76
|
-
/**
|
|
77
|
-
* Derive a NfcStatusCode from an error thrown during NFC operations.
|
|
78
|
-
* Handles iOS-specific cancel detection, known error strings, and fallback.
|
|
79
|
-
*/
|
|
80
|
-
export declare function errorToCode(error: any): number;
|