@ukeyfe/react-native-nfc-litecard 1.0.2 → 1.0.4
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/README.md +71 -34
- package/README.zh.md +275 -238
- package/dist/constants.d.ts +26 -0
- package/dist/constants.js +33 -1
- package/dist/crypto.d.ts +22 -0
- package/dist/crypto.js +165 -15
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -3
- package/dist/nfc-core.d.ts +9 -0
- package/dist/nfc-core.js +105 -9
- package/dist/reader.d.ts +13 -2
- package/dist/reader.js +153 -66
- package/dist/types.d.ts +16 -4
- package/dist/types.js +26 -24
- package/dist/utils.d.ts +16 -0
- package/dist/utils.js +36 -28
- package/dist/writer.d.ts +9 -4
- package/dist/writer.js +96 -87
- package/package.json +1 -1
package/dist/writer.d.ts
CHANGED
|
@@ -10,13 +10,18 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Based on MIFARE Ultralight AES (MF0AES(H)20) datasheet.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { NfcStatusCode, type NfcResult } from './types';
|
|
14
14
|
import { isNfcOperationLocked, releaseNfcOperationLock } from './nfc-core';
|
|
15
|
-
export {
|
|
15
|
+
export { NfcStatusCode, type NfcResult, isNfcOperationLocked, releaseNfcOperationLock };
|
|
16
16
|
/**
|
|
17
|
-
* Initialize a
|
|
17
|
+
* Initialize a card: authenticate with the default password, then write
|
|
18
|
+
* mnemonic and set a new password.
|
|
19
|
+
*
|
|
20
|
+
* @param mnemonic BIP-39 mnemonic to write.
|
|
21
|
+
* @param newPassword Password to protect the card with after initialization.
|
|
22
|
+
* @param defaultPassword Current (factory-default) password on the card.
|
|
18
23
|
*/
|
|
19
|
-
export declare function initializeCard(mnemonic: string,
|
|
24
|
+
export declare function initializeCard(mnemonic: string, newPassword: string, defaultPassword: string, onCardIdentified?: () => void): Promise<NfcResult>;
|
|
20
25
|
/**
|
|
21
26
|
* Update card: authenticate with old password, then write new mnemonic + new password.
|
|
22
27
|
*
|
package/dist/writer.js
CHANGED
|
@@ -44,22 +44,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
44
44
|
return result;
|
|
45
45
|
};
|
|
46
46
|
})();
|
|
47
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
48
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
49
|
-
};
|
|
50
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.releaseNfcOperationLock = exports.isNfcOperationLocked = exports.
|
|
48
|
+
exports.releaseNfcOperationLock = exports.isNfcOperationLocked = exports.NfcStatusCode = void 0;
|
|
52
49
|
exports.initializeCard = initializeCard;
|
|
53
50
|
exports.updateCard = updateCard;
|
|
54
51
|
exports.updatePassword = updatePassword;
|
|
55
52
|
exports.writeUserNickname = writeUserNickname;
|
|
56
53
|
exports.resetCard = resetCard;
|
|
57
|
-
const react_native_nfc_manager_1 = __importDefault(require("react-native-nfc-manager"));
|
|
58
54
|
const react_native_1 = require("react-native");
|
|
59
55
|
const bip39 = __importStar(require("bip39"));
|
|
60
56
|
const constants_1 = require("./constants");
|
|
61
57
|
const types_1 = require("./types");
|
|
62
|
-
Object.defineProperty(exports, "
|
|
58
|
+
Object.defineProperty(exports, "NfcStatusCode", { enumerable: true, get: function () { return types_1.NfcStatusCode; } });
|
|
63
59
|
const utils_1 = require("./utils");
|
|
64
60
|
const crypto_1 = require("./crypto");
|
|
65
61
|
const nfc_core_1 = require("./nfc-core");
|
|
@@ -91,24 +87,17 @@ async function writeUserMemory(data) {
|
|
|
91
87
|
const pageData = Array.from(buffer.slice(offset, offset + constants_1.PAGE_SIZE));
|
|
92
88
|
await writePage(page, pageData);
|
|
93
89
|
if (react_native_1.Platform.OS === 'ios' && i < totalPages - 1) {
|
|
94
|
-
await new Promise(r => setTimeout(r,
|
|
90
|
+
await new Promise(r => setTimeout(r, constants_1.DELAY.IOS_PAGE_WRITE));
|
|
95
91
|
// Keep-alive every 4 pages to prevent iOS session timeout
|
|
96
|
-
if ((i + 1) %
|
|
92
|
+
if ((i + 1) % constants_1.DELAY.KEEPALIVE_FREQ === 0) {
|
|
97
93
|
try {
|
|
98
|
-
await
|
|
94
|
+
await (0, nfc_core_1.transceive)([constants_1.CMD_READ, 0x00]);
|
|
99
95
|
}
|
|
100
96
|
catch { /* non-fatal */ }
|
|
101
97
|
}
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
100
|
}
|
|
105
|
-
/** FAST_READ pages 0x08–0x27 (user memory). */
|
|
106
|
-
async function readUserMemory() {
|
|
107
|
-
const response = await (0, nfc_core_1.transceive)([constants_1.CMD_FAST_READ, constants_1.USER_PAGE_START, constants_1.USER_PAGE_END]);
|
|
108
|
-
if (!response || response.length < constants_1.USER_MEMORY_SIZE)
|
|
109
|
-
throw new Error('READ_FAILED');
|
|
110
|
-
return new Uint8Array(response.slice(0, constants_1.USER_MEMORY_SIZE));
|
|
111
|
-
}
|
|
112
101
|
/**
|
|
113
102
|
* Write a 16-byte AES key to AES_KEY0 (pages 0x30–0x33).
|
|
114
103
|
* Byte order is reversed per the datasheet.
|
|
@@ -120,7 +109,7 @@ async function writeAesKey(key) {
|
|
|
120
109
|
const pageData = [key[off + 3], key[off + 2], key[off + 1], key[off + 0]];
|
|
121
110
|
await writePage(page, pageData);
|
|
122
111
|
if (react_native_1.Platform.OS === 'ios' && i < 3)
|
|
123
|
-
await new Promise(r => setTimeout(r,
|
|
112
|
+
await new Promise(r => setTimeout(r, constants_1.DELAY.IOS_KEY_WRITE));
|
|
124
113
|
}
|
|
125
114
|
}
|
|
126
115
|
/** Write a UTF-8 nickname into the last 3 pages of user memory. */
|
|
@@ -139,19 +128,20 @@ async function writeNicknameToCard(nickname) {
|
|
|
139
128
|
const offset = i * constants_1.PAGE_SIZE;
|
|
140
129
|
await writePage(page, Array.from(buffer.slice(offset, offset + constants_1.PAGE_SIZE)));
|
|
141
130
|
if (react_native_1.Platform.OS === 'ios' && i < totalPages - 1)
|
|
142
|
-
await new Promise(r => setTimeout(r,
|
|
131
|
+
await new Promise(r => setTimeout(r, constants_1.DELAY.IOS_NICKNAME_WRITE));
|
|
143
132
|
}
|
|
144
133
|
}
|
|
145
134
|
// ===========================================================================
|
|
146
135
|
// Auth configuration
|
|
147
136
|
// ===========================================================================
|
|
148
|
-
/** Enable read+write protection starting from USER_PAGE_START. */
|
|
137
|
+
/** Enable read+write protection and secure messaging starting from USER_PAGE_START. */
|
|
149
138
|
async function configureAuth() {
|
|
150
139
|
const cfg0 = await readPage(constants_1.PAGE_CFG0);
|
|
140
|
+
cfg0[0] = cfg0[0] | constants_1.SEC_MSG_ACT_MASK; // Enable CMAC secure messaging
|
|
151
141
|
cfg0[3] = constants_1.USER_PAGE_START;
|
|
152
142
|
await writePage(constants_1.PAGE_CFG0, cfg0.slice(0, 4));
|
|
153
143
|
if (react_native_1.Platform.OS === 'ios')
|
|
154
|
-
await new Promise(r => setTimeout(r,
|
|
144
|
+
await new Promise(r => setTimeout(r, constants_1.DELAY.IOS_CONFIG));
|
|
155
145
|
const cfg1 = await readPage(constants_1.PAGE_CFG1);
|
|
156
146
|
cfg1[0] = cfg1[0] | 0x80; // PROT bit = 1
|
|
157
147
|
await writePage(constants_1.PAGE_CFG1, cfg1.slice(0, 4));
|
|
@@ -168,7 +158,7 @@ async function disableAuth() {
|
|
|
168
158
|
cfg0[3] = 0x3c;
|
|
169
159
|
await writePage(constants_1.PAGE_CFG0, cfg0.slice(0, 4));
|
|
170
160
|
if (react_native_1.Platform.OS === 'ios')
|
|
171
|
-
await new Promise(r => setTimeout(r,
|
|
161
|
+
await new Promise(r => setTimeout(r, constants_1.DELAY.IOS_CONFIG));
|
|
172
162
|
const cfg1 = await readPage(constants_1.PAGE_CFG1);
|
|
173
163
|
cfg1[0] = cfg1[0] & 0x7f; // Clear PROT bit
|
|
174
164
|
await writePage(constants_1.PAGE_CFG1, cfg1.slice(0, 4));
|
|
@@ -185,31 +175,7 @@ function mnemonicToEntropyWithCRC(mnemonic) {
|
|
|
185
175
|
throw new Error('INVALID_MNEMONIC');
|
|
186
176
|
const entropyHex = bip39.mnemonicToEntropy(mnemonic);
|
|
187
177
|
const entropyBytes = (0, utils_1.hexToBytes)(entropyHex);
|
|
188
|
-
|
|
189
|
-
let typeStr;
|
|
190
|
-
switch (entropyBytes.length) {
|
|
191
|
-
case 16:
|
|
192
|
-
typeId = constants_1.MNEMONIC_TYPE_12;
|
|
193
|
-
typeStr = '12 words (128-bit)';
|
|
194
|
-
break;
|
|
195
|
-
case 20:
|
|
196
|
-
typeId = constants_1.MNEMONIC_TYPE_15;
|
|
197
|
-
typeStr = '15 words (160-bit)';
|
|
198
|
-
break;
|
|
199
|
-
case 24:
|
|
200
|
-
typeId = constants_1.MNEMONIC_TYPE_18;
|
|
201
|
-
typeStr = '18 words (192-bit)';
|
|
202
|
-
break;
|
|
203
|
-
case 28:
|
|
204
|
-
typeId = constants_1.MNEMONIC_TYPE_21;
|
|
205
|
-
typeStr = '21 words (224-bit)';
|
|
206
|
-
break;
|
|
207
|
-
case 32:
|
|
208
|
-
typeId = constants_1.MNEMONIC_TYPE_24;
|
|
209
|
-
typeStr = '24 words (256-bit)';
|
|
210
|
-
break;
|
|
211
|
-
default: throw new Error('UNSUPPORTED_MNEMONIC_LENGTH');
|
|
212
|
-
}
|
|
178
|
+
const { typeId, description: typeStr } = (0, utils_1.getMnemonicTypeByEntropyLength)(entropyBytes.length);
|
|
213
179
|
const dataBlock = new Uint8Array(1 + entropyBytes.length);
|
|
214
180
|
dataBlock[0] = typeId;
|
|
215
181
|
dataBlock.set(entropyBytes, 1);
|
|
@@ -223,46 +189,72 @@ function mnemonicToEntropyWithCRC(mnemonic) {
|
|
|
223
189
|
// Public API
|
|
224
190
|
// ===========================================================================
|
|
225
191
|
/**
|
|
226
|
-
* Initialize a
|
|
192
|
+
* Initialize a card: authenticate with the default password, then write
|
|
193
|
+
* mnemonic and set a new password.
|
|
194
|
+
*
|
|
195
|
+
* @param mnemonic BIP-39 mnemonic to write.
|
|
196
|
+
* @param newPassword Password to protect the card with after initialization.
|
|
197
|
+
* @param defaultPassword Current (factory-default) password on the card.
|
|
227
198
|
*/
|
|
228
|
-
async function initializeCard(mnemonic,
|
|
199
|
+
async function initializeCard(mnemonic, newPassword, defaultPassword, onCardIdentified) {
|
|
229
200
|
try {
|
|
230
201
|
await (0, nfc_core_1.acquireNfcLock)();
|
|
231
202
|
}
|
|
232
203
|
catch {
|
|
233
|
-
return { code: types_1.
|
|
204
|
+
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
234
205
|
}
|
|
206
|
+
let retryCountAfterPreDecrement;
|
|
235
207
|
try {
|
|
236
208
|
try {
|
|
237
209
|
await (0, nfc_core_1.requestNfcTech)();
|
|
238
210
|
}
|
|
239
211
|
catch {
|
|
240
212
|
(0, nfc_core_1.releaseNfcLock)();
|
|
241
|
-
return { code: types_1.
|
|
213
|
+
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
242
214
|
}
|
|
243
215
|
try {
|
|
244
216
|
const entropyResult = mnemonicToEntropyWithCRC(mnemonic);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
217
|
+
// Decrement retry counter before auth
|
|
218
|
+
try {
|
|
219
|
+
const n = await (0, nfc_core_1.decrementRetryCountInSession)();
|
|
220
|
+
if (typeof n === 'number')
|
|
221
|
+
retryCountAfterPreDecrement = n;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
const code = (0, types_1.errorToCode)(error);
|
|
225
|
+
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
226
|
+
await (0, nfc_core_1.releaseNfcTech)();
|
|
227
|
+
(0, nfc_core_1.releaseNfcLock)();
|
|
228
|
+
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Authenticate with factory-default password
|
|
232
|
+
const oldKey = (0, crypto_1.passwordToAesKey)(defaultPassword);
|
|
233
|
+
await (0, nfc_core_1.authenticate)(oldKey);
|
|
234
|
+
// Auth succeeded – reset retry counter
|
|
251
235
|
try {
|
|
252
236
|
await (0, nfc_core_1.writeRetryCountInSession)(constants_1.DEFAULT_PIN_RETRY_COUNT);
|
|
237
|
+
retryCountAfterPreDecrement = constants_1.DEFAULT_PIN_RETRY_COUNT;
|
|
253
238
|
}
|
|
254
239
|
catch { /* non-fatal */ }
|
|
240
|
+
onCardIdentified?.();
|
|
241
|
+
// Write mnemonic (while still authenticated)
|
|
242
|
+
await writeUserMemory(entropyResult.data);
|
|
243
|
+
// Switch to new password
|
|
244
|
+
const newKey = (0, crypto_1.passwordToAesKey)(newPassword);
|
|
245
|
+
await disableAuth();
|
|
246
|
+
await writeAesKey(newKey);
|
|
247
|
+
await configureAuth();
|
|
255
248
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
256
249
|
(0, nfc_core_1.releaseNfcLock)();
|
|
257
250
|
return {
|
|
258
|
-
code: types_1.
|
|
251
|
+
code: types_1.NfcStatusCode.INIT_SUCCESS,
|
|
259
252
|
success: true,
|
|
260
253
|
data: {
|
|
261
254
|
type: entropyResult.type,
|
|
262
255
|
entropyHex: entropyResult.entropyHex,
|
|
263
256
|
rawBytes: entropyResult.rawBytes,
|
|
264
257
|
crc16: entropyResult.crc16,
|
|
265
|
-
aesKeyHex,
|
|
266
258
|
retryCount: constants_1.DEFAULT_PIN_RETRY_COUNT,
|
|
267
259
|
},
|
|
268
260
|
};
|
|
@@ -271,7 +263,11 @@ async function initializeCard(mnemonic, password, onCardIdentified) {
|
|
|
271
263
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
272
264
|
(0, nfc_core_1.releaseNfcLock)();
|
|
273
265
|
const code = (0, types_1.errorToCode)(error);
|
|
274
|
-
return {
|
|
266
|
+
return {
|
|
267
|
+
code,
|
|
268
|
+
success: false,
|
|
269
|
+
data: typeof retryCountAfterPreDecrement === 'number' ? { retryCount: retryCountAfterPreDecrement } : undefined,
|
|
270
|
+
};
|
|
275
271
|
}
|
|
276
272
|
}
|
|
277
273
|
catch (error) {
|
|
@@ -292,7 +288,7 @@ async function updateCard(oldPassword, newPassword, newMnemonic, onCardIdentifie
|
|
|
292
288
|
await (0, nfc_core_1.acquireNfcLock)();
|
|
293
289
|
}
|
|
294
290
|
catch {
|
|
295
|
-
return { code: types_1.
|
|
291
|
+
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
296
292
|
}
|
|
297
293
|
let retryCountAfterPreDecrement;
|
|
298
294
|
try {
|
|
@@ -301,7 +297,7 @@ async function updateCard(oldPassword, newPassword, newMnemonic, onCardIdentifie
|
|
|
301
297
|
}
|
|
302
298
|
catch {
|
|
303
299
|
(0, nfc_core_1.releaseNfcLock)();
|
|
304
|
-
return { code: types_1.
|
|
300
|
+
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
305
301
|
}
|
|
306
302
|
try {
|
|
307
303
|
try {
|
|
@@ -311,7 +307,7 @@ async function updateCard(oldPassword, newPassword, newMnemonic, onCardIdentifie
|
|
|
311
307
|
}
|
|
312
308
|
catch (error) {
|
|
313
309
|
const code = (0, types_1.errorToCode)(error);
|
|
314
|
-
if (code === types_1.
|
|
310
|
+
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
315
311
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
316
312
|
(0, nfc_core_1.releaseNfcLock)();
|
|
317
313
|
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
@@ -328,21 +324,21 @@ async function updateCard(oldPassword, newPassword, newMnemonic, onCardIdentifie
|
|
|
328
324
|
onCardIdentified?.();
|
|
329
325
|
if (options?.precheckExistingMnemonic) {
|
|
330
326
|
try {
|
|
331
|
-
const data = await readUserMemory();
|
|
327
|
+
const data = await (0, nfc_core_1.readUserMemory)();
|
|
332
328
|
const decoded = (0, utils_1.validateMnemonicPayload)(data);
|
|
333
329
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
334
330
|
(0, nfc_core_1.releaseNfcLock)();
|
|
335
331
|
return {
|
|
336
|
-
code: types_1.
|
|
332
|
+
code: types_1.NfcStatusCode.PRECHECK_HAS_BACKUP,
|
|
337
333
|
success: true,
|
|
338
334
|
data: { type: decoded.type, retryCount: constants_1.DEFAULT_PIN_RETRY_COUNT },
|
|
339
335
|
};
|
|
340
336
|
}
|
|
341
337
|
catch (e) {
|
|
342
338
|
const c = (0, types_1.errorToCode)(e);
|
|
343
|
-
if (c === types_1.
|
|
344
|
-
c === types_1.
|
|
345
|
-
c === types_1.
|
|
339
|
+
if (c === types_1.NfcStatusCode.CHECK_EMPTY ||
|
|
340
|
+
c === types_1.NfcStatusCode.CRC16_CHECK_FAILED ||
|
|
341
|
+
c === types_1.NfcStatusCode.INVALID_CARD_DATA) {
|
|
346
342
|
// No valid mnemonic on card — fall through to write
|
|
347
343
|
}
|
|
348
344
|
else {
|
|
@@ -362,7 +358,7 @@ async function updateCard(oldPassword, newPassword, newMnemonic, onCardIdentifie
|
|
|
362
358
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
363
359
|
(0, nfc_core_1.releaseNfcLock)();
|
|
364
360
|
return {
|
|
365
|
-
code: types_1.
|
|
361
|
+
code: types_1.NfcStatusCode.WRITE_SUCCESS,
|
|
366
362
|
success: true,
|
|
367
363
|
data: {
|
|
368
364
|
type: entropyResult.type,
|
|
@@ -397,7 +393,7 @@ async function updatePassword(oldPassword, newPassword, onCardIdentified) {
|
|
|
397
393
|
await (0, nfc_core_1.acquireNfcLock)();
|
|
398
394
|
}
|
|
399
395
|
catch {
|
|
400
|
-
return { code: types_1.
|
|
396
|
+
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
401
397
|
}
|
|
402
398
|
let retryCountAfterPreDecrement;
|
|
403
399
|
try {
|
|
@@ -406,7 +402,7 @@ async function updatePassword(oldPassword, newPassword, onCardIdentified) {
|
|
|
406
402
|
}
|
|
407
403
|
catch {
|
|
408
404
|
(0, nfc_core_1.releaseNfcLock)();
|
|
409
|
-
return { code: types_1.
|
|
405
|
+
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
410
406
|
}
|
|
411
407
|
try {
|
|
412
408
|
try {
|
|
@@ -416,7 +412,7 @@ async function updatePassword(oldPassword, newPassword, onCardIdentified) {
|
|
|
416
412
|
}
|
|
417
413
|
catch (error) {
|
|
418
414
|
const code = (0, types_1.errorToCode)(error);
|
|
419
|
-
if (code === types_1.
|
|
415
|
+
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
420
416
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
421
417
|
(0, nfc_core_1.releaseNfcLock)();
|
|
422
418
|
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
@@ -439,7 +435,7 @@ async function updatePassword(oldPassword, newPassword, onCardIdentified) {
|
|
|
439
435
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
440
436
|
(0, nfc_core_1.releaseNfcLock)();
|
|
441
437
|
return {
|
|
442
|
-
code: types_1.
|
|
438
|
+
code: types_1.NfcStatusCode.UPDATE_PASSWORD_SUCCESS,
|
|
443
439
|
success: true,
|
|
444
440
|
data: { aesKeyHex, retryCount: constants_1.DEFAULT_PIN_RETRY_COUNT },
|
|
445
441
|
};
|
|
@@ -466,7 +462,7 @@ async function writeUserNickname(password, nickname, onCardIdentified) {
|
|
|
466
462
|
await (0, nfc_core_1.acquireNfcLock)();
|
|
467
463
|
}
|
|
468
464
|
catch {
|
|
469
|
-
return { code: types_1.
|
|
465
|
+
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
470
466
|
}
|
|
471
467
|
try {
|
|
472
468
|
try {
|
|
@@ -474,11 +470,28 @@ async function writeUserNickname(password, nickname, onCardIdentified) {
|
|
|
474
470
|
}
|
|
475
471
|
catch {
|
|
476
472
|
(0, nfc_core_1.releaseNfcLock)();
|
|
477
|
-
return { code: types_1.
|
|
473
|
+
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
478
474
|
}
|
|
479
475
|
try {
|
|
476
|
+
// Pre-decrement retry counter before auth
|
|
477
|
+
try {
|
|
478
|
+
await (0, nfc_core_1.decrementRetryCountInSession)();
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
const code = (0, types_1.errorToCode)(error);
|
|
482
|
+
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
483
|
+
await (0, nfc_core_1.releaseNfcTech)();
|
|
484
|
+
(0, nfc_core_1.releaseNfcLock)();
|
|
485
|
+
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
480
488
|
const aesKey = (0, crypto_1.passwordToAesKey)(password);
|
|
481
489
|
await (0, nfc_core_1.authenticate)(aesKey);
|
|
490
|
+
// Auth succeeded – reset retry counter
|
|
491
|
+
try {
|
|
492
|
+
await (0, nfc_core_1.writeRetryCountInSession)(constants_1.DEFAULT_PIN_RETRY_COUNT);
|
|
493
|
+
}
|
|
494
|
+
catch { /* non-fatal */ }
|
|
482
495
|
onCardIdentified?.();
|
|
483
496
|
await disableAuth();
|
|
484
497
|
await writeNicknameToCard(nickname);
|
|
@@ -486,7 +499,7 @@ async function writeUserNickname(password, nickname, onCardIdentified) {
|
|
|
486
499
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
487
500
|
(0, nfc_core_1.releaseNfcLock)();
|
|
488
501
|
return {
|
|
489
|
-
code: types_1.
|
|
502
|
+
code: types_1.NfcStatusCode.WRITE_NICKNAME_SUCCESS,
|
|
490
503
|
success: true,
|
|
491
504
|
};
|
|
492
505
|
}
|
|
@@ -513,7 +526,7 @@ async function resetCard(password, newPassword, onCardIdentified) {
|
|
|
513
526
|
await (0, nfc_core_1.acquireNfcLock)();
|
|
514
527
|
}
|
|
515
528
|
catch {
|
|
516
|
-
return { code: types_1.
|
|
529
|
+
return { code: types_1.NfcStatusCode.UNKNOWN_ERROR, success: false };
|
|
517
530
|
}
|
|
518
531
|
let retryCountAfterPreDecrement;
|
|
519
532
|
try {
|
|
@@ -522,7 +535,7 @@ async function resetCard(password, newPassword, onCardIdentified) {
|
|
|
522
535
|
}
|
|
523
536
|
catch {
|
|
524
537
|
(0, nfc_core_1.releaseNfcLock)();
|
|
525
|
-
return { code: types_1.
|
|
538
|
+
return { code: types_1.NfcStatusCode.NFC_CONNECT_FAILED, success: false };
|
|
526
539
|
}
|
|
527
540
|
try {
|
|
528
541
|
if (password) {
|
|
@@ -533,7 +546,7 @@ async function resetCard(password, newPassword, onCardIdentified) {
|
|
|
533
546
|
}
|
|
534
547
|
catch (error) {
|
|
535
548
|
const code = (0, types_1.errorToCode)(error);
|
|
536
|
-
if (code === types_1.
|
|
549
|
+
if (code === types_1.NfcStatusCode.RETRY_COUNT_EXHAUSTED) {
|
|
537
550
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
538
551
|
(0, nfc_core_1.releaseNfcLock)();
|
|
539
552
|
return (0, types_1.nfcResultRetryCountExhausted)();
|
|
@@ -565,11 +578,10 @@ async function resetCard(password, newPassword, onCardIdentified) {
|
|
|
565
578
|
}
|
|
566
579
|
catch { /* non-fatal */ }
|
|
567
580
|
}
|
|
568
|
-
await disableAuth();
|
|
569
581
|
}
|
|
570
582
|
else {
|
|
571
583
|
try {
|
|
572
|
-
await
|
|
584
|
+
await (0, nfc_core_1.authenticate)((0, crypto_1.passwordToAesKey)(newPassword));
|
|
573
585
|
}
|
|
574
586
|
catch {
|
|
575
587
|
throw new Error('AUTH_WRONG_PASSWORD');
|
|
@@ -578,18 +590,15 @@ async function resetCard(password, newPassword, onCardIdentified) {
|
|
|
578
590
|
}
|
|
579
591
|
// Wipe mnemonic data (nickname is preserved)
|
|
580
592
|
await writeUserMemory(new Uint8Array(constants_1.MNEMONIC_MEMORY_SIZE));
|
|
581
|
-
// Set new password
|
|
593
|
+
// Set new password and keep protection enabled
|
|
582
594
|
const resetKey = (0, crypto_1.passwordToAesKey)(newPassword);
|
|
595
|
+
await disableAuth();
|
|
583
596
|
await writeAesKey(resetKey);
|
|
584
|
-
|
|
585
|
-
try {
|
|
586
|
-
await disableAuth();
|
|
587
|
-
}
|
|
588
|
-
catch { /* may already be off */ }
|
|
597
|
+
await configureAuth();
|
|
589
598
|
await (0, nfc_core_1.releaseNfcTech)();
|
|
590
599
|
(0, nfc_core_1.releaseNfcLock)();
|
|
591
600
|
return {
|
|
592
|
-
code: types_1.
|
|
601
|
+
code: types_1.NfcStatusCode.RESET_SUCCESS,
|
|
593
602
|
success: true,
|
|
594
603
|
data: { retryCount: constants_1.DEFAULT_PIN_RETRY_COUNT },
|
|
595
604
|
};
|