zklib-ts 1.0.4 → 1.0.6
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 +18 -0
- package/dist/helper/command.d.ts +177 -85
- package/dist/index.cjs.js +805 -480
- package/dist/index.d.ts +47 -6
- package/dist/index.es.js +805 -480
- package/dist/models/Attendance.d.ts +7 -2
- package/dist/services/transaction.service.d.ts +9 -0
- package/dist/services/user.service.d.ts +33 -0
- package/dist/ztcp.d.ts +22 -31
- package/dist/zudp.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -5,99 +5,190 @@ import * as dgram from 'node:dgram';
|
|
|
5
5
|
var COMMANDS;
|
|
6
6
|
(function (COMMANDS) {
|
|
7
7
|
COMMANDS[COMMANDS["CMD_ACK_DATA"] = 2002] = "CMD_ACK_DATA";
|
|
8
|
+
/** There was an error when processing the request.*/
|
|
8
9
|
COMMANDS[COMMANDS["CMD_ACK_ERROR"] = 2001] = "CMD_ACK_ERROR";
|
|
9
10
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_CMD"] = 65533] = "CMD_ACK_ERROR_CMD";
|
|
10
11
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_DATA"] = 65531] = "CMD_ACK_ERROR_DATA";
|
|
11
12
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_INIT"] = 65532] = "CMD_ACK_ERROR_INIT";
|
|
13
|
+
/** [0xD0, 0x07] The request was processed sucessfully. */
|
|
12
14
|
COMMANDS[COMMANDS["CMD_ACK_OK"] = 2000] = "CMD_ACK_OK";
|
|
13
15
|
COMMANDS[COMMANDS["CMD_ACK_REPEAT"] = 2004] = "CMD_ACK_REPEAT";
|
|
14
16
|
COMMANDS[COMMANDS["CMD_ACK_RETRY"] = 2003] = "CMD_ACK_RETRY";
|
|
17
|
+
/** [0xD5, 0x07] Connection not authorized. */
|
|
15
18
|
COMMANDS[COMMANDS["CMD_ACK_UNAUTH"] = 2005] = "CMD_ACK_UNAUTH";
|
|
19
|
+
/** Received unknown command. */
|
|
16
20
|
COMMANDS[COMMANDS["CMD_ACK_UNKNOWN"] = 65535] = "CMD_ACK_UNKNOWN";
|
|
21
|
+
/** Request attendance log. */
|
|
17
22
|
COMMANDS[COMMANDS["CMD_ATTLOG_RRQ"] = 13] = "CMD_ATTLOG_RRQ";
|
|
23
|
+
/** [0x4E, 0x04] Request to begin session using commkey. */
|
|
18
24
|
COMMANDS[COMMANDS["CMD_AUTH"] = 1102] = "CMD_AUTH";
|
|
25
|
+
/** Disable normal authentication of users. */
|
|
19
26
|
COMMANDS[COMMANDS["CMD_CANCELCAPTURE"] = 62] = "CMD_CANCELCAPTURE";
|
|
27
|
+
/** Capture fingerprint picture. */
|
|
20
28
|
COMMANDS[COMMANDS["CMD_CAPTUREFINGER"] = 1009] = "CMD_CAPTUREFINGER";
|
|
29
|
+
/** Capture the entire image. */
|
|
21
30
|
COMMANDS[COMMANDS["CMD_CAPTUREIMAGE"] = 1012] = "CMD_CAPTUREIMAGE";
|
|
31
|
+
/** Change transmission speed. */
|
|
22
32
|
COMMANDS[COMMANDS["CMD_CHANGE_SPEED"] = 1101] = "CMD_CHANGE_SPEED";
|
|
33
|
+
/** [0x77, 0x00] Get checksum of machine's buffer. */
|
|
23
34
|
COMMANDS[COMMANDS["CMD_CHECKSUM_BUFFER"] = 119] = "CMD_CHECKSUM_BUFFER";
|
|
35
|
+
/** Restore access control to default. */
|
|
24
36
|
COMMANDS[COMMANDS["CMD_CLEAR_ACC"] = 32] = "CMD_CLEAR_ACC";
|
|
37
|
+
/** Clears admins privileges. */
|
|
25
38
|
COMMANDS[COMMANDS["CMD_CLEAR_ADMIN"] = 20] = "CMD_CLEAR_ADMIN";
|
|
39
|
+
/** Delete attendance record. */
|
|
26
40
|
COMMANDS[COMMANDS["CMD_CLEAR_ATTLOG"] = 15] = "CMD_CLEAR_ATTLOG";
|
|
41
|
+
/** Delete data. */
|
|
27
42
|
COMMANDS[COMMANDS["CMD_CLEAR_DATA"] = 14] = "CMD_CLEAR_DATA";
|
|
43
|
+
/** Clear screen captions. */
|
|
28
44
|
COMMANDS[COMMANDS["CMD_CLEAR_LCD"] = 67] = "CMD_CLEAR_LCD";
|
|
45
|
+
/** Delete operations log. */
|
|
29
46
|
COMMANDS[COMMANDS["CMD_CLEAR_OPLOG"] = 33] = "CMD_CLEAR_OPLOG";
|
|
47
|
+
/** [0xE8, 0x03] Begin connection. */
|
|
30
48
|
COMMANDS[COMMANDS["CMD_CONNECT"] = 1000] = "CMD_CONNECT";
|
|
49
|
+
/** [0xDD, 0x05] Data packet. */
|
|
31
50
|
COMMANDS[COMMANDS["CMD_DATA"] = 1501] = "CMD_DATA";
|
|
51
|
+
/** Indicates that it is ready to receive data. */
|
|
32
52
|
COMMANDS[COMMANDS["CMD_DATA_RDY"] = 1504] = "CMD_DATA_RDY";
|
|
53
|
+
/** Read/Write a large data set. */
|
|
33
54
|
COMMANDS[COMMANDS["CMD_DATA_WRRQ"] = 1503] = "CMD_DATA_WRRQ";
|
|
55
|
+
/** Read saved data. */
|
|
34
56
|
COMMANDS[COMMANDS["CMD_DB_RRQ"] = 7] = "CMD_DB_RRQ";
|
|
57
|
+
/** Deletes fingerprint template. */
|
|
35
58
|
COMMANDS[COMMANDS["CMD_DEL_FPTMP"] = 134] = "CMD_DEL_FPTMP";
|
|
59
|
+
/** Delete short message. */
|
|
36
60
|
COMMANDS[COMMANDS["CMD_DELETE_SMS"] = 72] = "CMD_DELETE_SMS";
|
|
61
|
+
/** Delete user short message. */
|
|
37
62
|
COMMANDS[COMMANDS["CMD_DELETE_UDATA"] = 74] = "CMD_DELETE_UDATA";
|
|
63
|
+
/** Delete user. */
|
|
38
64
|
COMMANDS[COMMANDS["CMD_DELETE_USER"] = 18] = "CMD_DELETE_USER";
|
|
65
|
+
/** Delete user fingerprint template. */
|
|
39
66
|
COMMANDS[COMMANDS["CMD_DELETE_USERTEMP"] = 19] = "CMD_DELETE_USERTEMP";
|
|
67
|
+
/** Disables fingerprint, rfid reader and keyboard. */
|
|
40
68
|
COMMANDS[COMMANDS["CMD_DISABLEDEVICE"] = 1003] = "CMD_DISABLEDEVICE";
|
|
69
|
+
/** Get door state. */
|
|
41
70
|
COMMANDS[COMMANDS["CMD_DOORSTATE_RRQ"] = 75] = "CMD_DOORSTATE_RRQ";
|
|
71
|
+
/** Clear Mifare card. */
|
|
42
72
|
COMMANDS[COMMANDS["CMD_EMPTY_MIFARE"] = 78] = "CMD_EMPTY_MIFARE";
|
|
73
|
+
/** Enables the ":" in screen clock. */
|
|
43
74
|
COMMANDS[COMMANDS["CMD_ENABLE_CLOCK"] = 57] = "CMD_ENABLE_CLOCK";
|
|
75
|
+
/** Change machine state to "normal work". */
|
|
44
76
|
COMMANDS[COMMANDS["CMD_ENABLEDEVICE"] = 1002] = "CMD_ENABLEDEVICE";
|
|
77
|
+
/** [0xE9, 0x03] Disconnect. */
|
|
45
78
|
COMMANDS[COMMANDS["CMD_EXIT"] = 1001] = "CMD_EXIT";
|
|
79
|
+
/** [0xDE, 0x05] Release buffer used for data transmission. */
|
|
46
80
|
COMMANDS[COMMANDS["CMD_FREE_DATA"] = 1502] = "CMD_FREE_DATA";
|
|
81
|
+
/** Request machine status (remaining space). */
|
|
47
82
|
COMMANDS[COMMANDS["CMD_GET_FREE_SIZES"] = 50] = "CMD_GET_FREE_SIZES";
|
|
83
|
+
/** Request max size for users id. */
|
|
48
84
|
COMMANDS[COMMANDS["CMD_GET_PINWIDTH"] = 69] = "CMD_GET_PINWIDTH";
|
|
85
|
+
/** Request machine time. */
|
|
49
86
|
COMMANDS[COMMANDS["CMD_GET_TIME"] = 201] = "CMD_GET_TIME";
|
|
50
87
|
COMMANDS[COMMANDS["CMD_GET_USERTEMP"] = 88] = "CMD_GET_USERTEMP";
|
|
88
|
+
/** Request the firmware edition. */
|
|
51
89
|
COMMANDS[COMMANDS["CMD_GET_VERSION"] = 1100] = "CMD_GET_VERSION";
|
|
90
|
+
/** Get group timezone. */
|
|
52
91
|
COMMANDS[COMMANDS["CMD_GRPTZ_RRQ"] = 25] = "CMD_GRPTZ_RRQ";
|
|
92
|
+
/** Set group timezone. */
|
|
53
93
|
COMMANDS[COMMANDS["CMD_GRPTZ_WRQ"] = 26] = "CMD_GRPTZ_WRQ";
|
|
94
|
+
/** Read operations log. */
|
|
54
95
|
COMMANDS[COMMANDS["CMD_OPLOG_RRQ"] = 34] = "CMD_OPLOG_RRQ";
|
|
96
|
+
/** Read configuration value of the machine. */
|
|
55
97
|
COMMANDS[COMMANDS["CMD_OPTIONS_RRQ"] = 11] = "CMD_OPTIONS_RRQ";
|
|
98
|
+
/** Change configuration value of the machine. */
|
|
56
99
|
COMMANDS[COMMANDS["CMD_OPTIONS_WRQ"] = 12] = "CMD_OPTIONS_WRQ";
|
|
100
|
+
/** Shut-down machine. */
|
|
57
101
|
COMMANDS[COMMANDS["CMD_POWEROFF"] = 1005] = "CMD_POWEROFF";
|
|
102
|
+
/** [0xDC, 0x05] Prepare for data transmission. */
|
|
58
103
|
COMMANDS[COMMANDS["CMD_PREPARE_DATA"] = 1500] = "CMD_PREPARE_DATA";
|
|
104
|
+
/** [0xF5, 0x03] Refresh the machine stored data. */
|
|
59
105
|
COMMANDS[COMMANDS["CMD_REFRESHDATA"] = 1013] = "CMD_REFRESHDATA";
|
|
106
|
+
/** Refresh the configuration parameters. */
|
|
60
107
|
COMMANDS[COMMANDS["CMD_REFRESHOPTION"] = 1014] = "CMD_REFRESHOPTION";
|
|
108
|
+
/** Realtime events. */
|
|
61
109
|
COMMANDS[COMMANDS["CMD_REG_EVENT"] = 500] = "CMD_REG_EVENT";
|
|
110
|
+
/** Restart machine. */
|
|
62
111
|
COMMANDS[COMMANDS["CMD_RESTART"] = 1004] = "CMD_RESTART";
|
|
112
|
+
/** Change machine state to "awaken". */
|
|
63
113
|
COMMANDS[COMMANDS["CMD_RESUME"] = 1007] = "CMD_RESUME";
|
|
114
|
+
/** Set machine time. */
|
|
64
115
|
COMMANDS[COMMANDS["CMD_SET_TIME"] = 202] = "CMD_SET_TIME";
|
|
116
|
+
/** Change machine state to "idle". */
|
|
65
117
|
COMMANDS[COMMANDS["CMD_SLEEP"] = 1006] = "CMD_SLEEP";
|
|
118
|
+
/** Download short message. */
|
|
66
119
|
COMMANDS[COMMANDS["CMD_SMS_RRQ"] = 71] = "CMD_SMS_RRQ";
|
|
120
|
+
/** Upload short message. */
|
|
67
121
|
COMMANDS[COMMANDS["CMD_SMS_WRQ"] = 70] = "CMD_SMS_WRQ";
|
|
122
|
+
/** Start enroll procedure. */
|
|
68
123
|
COMMANDS[COMMANDS["CMD_STARTENROLL"] = 61] = "CMD_STARTENROLL";
|
|
124
|
+
/** Set the machine to authentication state. */
|
|
69
125
|
COMMANDS[COMMANDS["CMD_STARTVERIFY"] = 60] = "CMD_STARTVERIFY";
|
|
126
|
+
/** Query state. */
|
|
70
127
|
COMMANDS[COMMANDS["CMD_STATE_RRQ"] = 64] = "CMD_STATE_RRQ";
|
|
128
|
+
/** Test if fingerprint exists. */
|
|
71
129
|
COMMANDS[COMMANDS["CMD_TEST_TEMP"] = 1011] = "CMD_TEST_TEMP";
|
|
130
|
+
/** Test voice. */
|
|
72
131
|
COMMANDS[COMMANDS["CMD_TESTVOICE"] = 1017] = "CMD_TESTVOICE";
|
|
132
|
+
/** [0x77, 0x00] Transfer fp template from buffer. */
|
|
73
133
|
COMMANDS[COMMANDS["CMD_TMP_WRITE"] = 87] = "CMD_TMP_WRITE";
|
|
134
|
+
/** Get device timezones. */
|
|
74
135
|
COMMANDS[COMMANDS["CMD_TZ_RRQ"] = 27] = "CMD_TZ_RRQ";
|
|
136
|
+
/** Set device timezones. */
|
|
75
137
|
COMMANDS[COMMANDS["CMD_TZ_WRQ"] = 28] = "CMD_TZ_WRQ";
|
|
138
|
+
/** Set user short message. */
|
|
76
139
|
COMMANDS[COMMANDS["CMD_UDATA_WRQ"] = 73] = "CMD_UDATA_WRQ";
|
|
140
|
+
/** Get group combination to unlock. */
|
|
77
141
|
COMMANDS[COMMANDS["CMD_ULG_RRQ"] = 29] = "CMD_ULG_RRQ";
|
|
142
|
+
/** Set group combination to unlock. */
|
|
78
143
|
COMMANDS[COMMANDS["CMD_ULG_WRQ"] = 30] = "CMD_ULG_WRQ";
|
|
144
|
+
/** Unlock door for a specified amount of time. */
|
|
79
145
|
COMMANDS[COMMANDS["CMD_UNLOCK"] = 31] = "CMD_UNLOCK";
|
|
146
|
+
/** Upload user data. */
|
|
80
147
|
COMMANDS[COMMANDS["CMD_USER_WRQ"] = 8] = "CMD_USER_WRQ";
|
|
148
|
+
/** Read user group. */
|
|
81
149
|
COMMANDS[COMMANDS["CMD_USERGRP_RRQ"] = 21] = "CMD_USERGRP_RRQ";
|
|
150
|
+
/** Set user group. */
|
|
82
151
|
COMMANDS[COMMANDS["CMD_USERGRP_WRQ"] = 22] = "CMD_USERGRP_WRQ";
|
|
152
|
+
/** [0x09, 0x00] Read user fingerprint template. */
|
|
83
153
|
COMMANDS[COMMANDS["CMD_USERTEMP_RRQ"] = 9] = "CMD_USERTEMP_RRQ";
|
|
154
|
+
/** Upload user fingerprint template. */
|
|
84
155
|
COMMANDS[COMMANDS["CMD_USERTEMP_WRQ"] = 10] = "CMD_USERTEMP_WRQ";
|
|
156
|
+
/** Get user timezones. */
|
|
85
157
|
COMMANDS[COMMANDS["CMD_USERTZ_RRQ"] = 23] = "CMD_USERTZ_RRQ";
|
|
158
|
+
/** Set the user timezones. */
|
|
86
159
|
COMMANDS[COMMANDS["CMD_USERTZ_WRQ"] = 24] = "CMD_USERTZ_WRQ";
|
|
160
|
+
/** Read verification style of a given user. */
|
|
87
161
|
COMMANDS[COMMANDS["CMD_VERIFY_RRQ"] = 80] = "CMD_VERIFY_RRQ";
|
|
162
|
+
/** Change verification style of a given user. */
|
|
88
163
|
COMMANDS[COMMANDS["CMD_VERIFY_WRQ"] = 79] = "CMD_VERIFY_WRQ";
|
|
164
|
+
/** Prints chars to the device screen. */
|
|
89
165
|
COMMANDS[COMMANDS["CMD_WRITE_LCD"] = 66] = "CMD_WRITE_LCD";
|
|
166
|
+
/** Write data to Mifare card. */
|
|
90
167
|
COMMANDS[COMMANDS["CMD_WRITE_MIFARE"] = 76] = "CMD_WRITE_MIFARE";
|
|
168
|
+
/** Triggered alarm. */
|
|
91
169
|
COMMANDS[COMMANDS["EF_ALARM"] = 512] = "EF_ALARM";
|
|
170
|
+
/** Attendance entry. */
|
|
92
171
|
COMMANDS[COMMANDS["EF_ATTLOG"] = 1] = "EF_ATTLOG";
|
|
172
|
+
/** Pressed keyboard key. */
|
|
93
173
|
COMMANDS[COMMANDS["EF_BUTTON"] = 16] = "EF_BUTTON";
|
|
174
|
+
/** Upload user data. */
|
|
94
175
|
COMMANDS[COMMANDS["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
|
|
176
|
+
/** Enrolled user. */
|
|
95
177
|
COMMANDS[COMMANDS["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
|
|
178
|
+
/** Pressed finger. */
|
|
96
179
|
COMMANDS[COMMANDS["EF_FINGER"] = 2] = "EF_FINGER";
|
|
180
|
+
/** Fingerprint score in enroll procedure. */
|
|
97
181
|
COMMANDS[COMMANDS["EF_FPFTR"] = 256] = "EF_FPFTR";
|
|
182
|
+
/** Restore access control to default. */
|
|
98
183
|
COMMANDS[COMMANDS["EF_UNLOCK"] = 32] = "EF_UNLOCK";
|
|
184
|
+
/** Registered user placed finger. */
|
|
99
185
|
COMMANDS[COMMANDS["EF_VERIFY"] = 128] = "EF_VERIFY";
|
|
100
186
|
})(COMMANDS || (COMMANDS = {}));
|
|
187
|
+
var DISCOVERED_CMD;
|
|
188
|
+
(function (DISCOVERED_CMD) {
|
|
189
|
+
/** Returned when the Finger id not exists in the user uid, when attempting to download single finger template */
|
|
190
|
+
DISCOVERED_CMD[DISCOVERED_CMD["FID_NOT_FOUND"] = 4993] = "FID_NOT_FOUND";
|
|
191
|
+
})(DISCOVERED_CMD || (DISCOVERED_CMD = {}));
|
|
101
192
|
var Constants;
|
|
102
193
|
(function (Constants) {
|
|
103
194
|
Constants[Constants["USHRT_MAX"] = 65535] = "USHRT_MAX";
|
|
@@ -106,6 +197,7 @@ var Constants;
|
|
|
106
197
|
Constants[Constants["MACHINE_PREPARE_DATA_2"] = 32130] = "MACHINE_PREPARE_DATA_2";
|
|
107
198
|
})(Constants || (Constants = {}));
|
|
108
199
|
const REQUEST_DATA = {
|
|
200
|
+
START_TAG: Buffer.from([0x50, 0x50, 0x82, 0x7d]),
|
|
109
201
|
DISABLE_DEVICE: Buffer.from([0, 0, 0, 0]),
|
|
110
202
|
GET_REAL_TIME_EVENT: Buffer.from([0x01, 0x00, 0x00, 0x00]),
|
|
111
203
|
GET_ATTENDANCE_LOGS: Buffer.from([0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
|
@@ -253,18 +345,23 @@ class User {
|
|
|
253
345
|
}
|
|
254
346
|
|
|
255
347
|
class Attendance {
|
|
348
|
+
/** Internal serial number for the user */
|
|
256
349
|
sn;
|
|
350
|
+
/** User ID/Pin stored as a string */
|
|
257
351
|
user_id;
|
|
258
|
-
|
|
352
|
+
/** Verification type */
|
|
259
353
|
type;
|
|
354
|
+
/** Time of the attendance event */
|
|
355
|
+
record_time;
|
|
356
|
+
/** Verify state */
|
|
260
357
|
state;
|
|
261
358
|
ip;
|
|
262
|
-
constructor(sn, user_id,
|
|
359
|
+
constructor(sn, user_id, type, record_time, state) {
|
|
263
360
|
this.sn = sn;
|
|
264
361
|
this.user_id = user_id;
|
|
362
|
+
this.type = type || undefined;
|
|
265
363
|
this.record_time = record_time;
|
|
266
|
-
this.
|
|
267
|
-
this.state = state;
|
|
364
|
+
this.state = state || undefined;
|
|
268
365
|
}
|
|
269
366
|
}
|
|
270
367
|
|
|
@@ -308,17 +405,7 @@ const createUDPHeader = (command, sessionId, replyId, data) => {
|
|
|
308
405
|
return buf;
|
|
309
406
|
};
|
|
310
407
|
const createTCPHeader = (command, sessionId, replyId, data) => {
|
|
311
|
-
const
|
|
312
|
-
const buf = Buffer.alloc(8 + dataBuffer.length);
|
|
313
|
-
buf.writeUInt16LE(command, 0);
|
|
314
|
-
buf.writeUInt16LE(0, 2);
|
|
315
|
-
buf.writeUInt16LE(sessionId, 4);
|
|
316
|
-
buf.writeUInt16LE(replyId, 6);
|
|
317
|
-
dataBuffer.copy(buf, 8);
|
|
318
|
-
const chksum2 = createChkSum(buf);
|
|
319
|
-
buf.writeUInt16LE(chksum2, 2);
|
|
320
|
-
replyId = (replyId + 1) % Constants.USHRT_MAX;
|
|
321
|
-
buf.writeUInt16LE(replyId, 6);
|
|
408
|
+
const buf = createUDPHeader(command, sessionId, replyId, data);
|
|
322
409
|
const prefixBuf = Buffer.from([0x50, 0x50, 0x82, 0x7d, 0x13, 0x00, 0x00, 0x00]);
|
|
323
410
|
prefixBuf.writeUInt16LE(buf.length, 4);
|
|
324
411
|
return Buffer.concat([prefixBuf, buf]);
|
|
@@ -378,7 +465,7 @@ const decodeRecordData40 = (recordData) => {
|
|
|
378
465
|
.slice(2, 2 + 9)
|
|
379
466
|
.toString('ascii')
|
|
380
467
|
.split('\0')
|
|
381
|
-
.shift() || '',
|
|
468
|
+
.shift() || '', recordData.readUIntLE(26, 1), parseTimeToDate(recordData.readUInt32LE(27)), recordData.readUIntLE(31, 1));
|
|
382
469
|
};
|
|
383
470
|
const decodeRecordData16 = (recordData) => {
|
|
384
471
|
return {
|
|
@@ -494,6 +581,59 @@ const authKey = (comKey, sessionId) => {
|
|
|
494
581
|
return Array.from(response);
|
|
495
582
|
};
|
|
496
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Error types for device communication
|
|
586
|
+
*/
|
|
587
|
+
const ERROR_TYPES = {
|
|
588
|
+
ECONNRESET: 'ECONNRESET',
|
|
589
|
+
ECONNREFUSED: 'ECONNREFUSED'};
|
|
590
|
+
/**
|
|
591
|
+
* Custom error class for device communication errors
|
|
592
|
+
*/
|
|
593
|
+
class ZkError {
|
|
594
|
+
err;
|
|
595
|
+
ip;
|
|
596
|
+
command;
|
|
597
|
+
/**
|
|
598
|
+
* Creates a new ZkError instance
|
|
599
|
+
* @param err The error object
|
|
600
|
+
* @param command The command that caused the error
|
|
601
|
+
* @param ip The IP address of the device
|
|
602
|
+
*/
|
|
603
|
+
constructor(err, command, ip) {
|
|
604
|
+
this.err = err;
|
|
605
|
+
this.ip = ip;
|
|
606
|
+
this.command = command;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Gets a user-friendly error message
|
|
610
|
+
* @returns A formatted error message
|
|
611
|
+
*/
|
|
612
|
+
toast() {
|
|
613
|
+
if (this.err.code === ERROR_TYPES.ECONNRESET) {
|
|
614
|
+
return 'Another device is connecting to the device so the connection is interrupted';
|
|
615
|
+
}
|
|
616
|
+
else if (this.err.code === ERROR_TYPES.ECONNREFUSED) {
|
|
617
|
+
return 'IP of the device is refused';
|
|
618
|
+
}
|
|
619
|
+
return this.err.message;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Gets detailed error information
|
|
623
|
+
* @returns An object containing error details
|
|
624
|
+
*/
|
|
625
|
+
getError() {
|
|
626
|
+
return {
|
|
627
|
+
err: {
|
|
628
|
+
message: this.err.message,
|
|
629
|
+
code: this.err.code
|
|
630
|
+
},
|
|
631
|
+
ip: this.ip,
|
|
632
|
+
command: this.command
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
497
637
|
/**
|
|
498
638
|
* Represents a fingerprint template with associated metadata
|
|
499
639
|
*/
|
|
@@ -567,56 +707,547 @@ class Finger {
|
|
|
567
707
|
}
|
|
568
708
|
}
|
|
569
709
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
710
|
+
class UserService {
|
|
711
|
+
_zkTcp;
|
|
712
|
+
_users;
|
|
713
|
+
constructor(zkTcp) {
|
|
714
|
+
this._zkTcp = zkTcp;
|
|
715
|
+
}
|
|
716
|
+
async getUserByUserId(user_id) {
|
|
717
|
+
if (!this._users) {
|
|
718
|
+
await this.getUsers();
|
|
719
|
+
}
|
|
720
|
+
if (this._users.has(String(user_id))) {
|
|
721
|
+
return this._users.get(String(user_id));
|
|
722
|
+
}
|
|
723
|
+
else
|
|
724
|
+
throw new Error("user_id not exists");
|
|
725
|
+
}
|
|
726
|
+
async getUsers() {
|
|
727
|
+
try {
|
|
728
|
+
// Free any existing buffer data to prepare for a new request
|
|
729
|
+
if (this._users) {
|
|
730
|
+
return { data: Array.from(this._users.values()) };
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
this._users = new Map([]);
|
|
734
|
+
}
|
|
735
|
+
if (this._zkTcp.socket) {
|
|
736
|
+
await this._zkTcp.freeData();
|
|
737
|
+
}
|
|
738
|
+
// Request user data
|
|
739
|
+
const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_USERS);
|
|
740
|
+
// Free buffer data after receiving the data
|
|
741
|
+
if (this._zkTcp.socket) {
|
|
742
|
+
await this._zkTcp.freeData();
|
|
743
|
+
}
|
|
744
|
+
// Constants for user data processing
|
|
745
|
+
const USER_PACKET_SIZE = 72;
|
|
746
|
+
// Ensure data.data is a valid buffer
|
|
747
|
+
if (!data.data || !(data.data instanceof Buffer)) {
|
|
748
|
+
throw new Error('Invalid data received');
|
|
749
|
+
}
|
|
750
|
+
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
751
|
+
const users = [];
|
|
752
|
+
// Process each user packet
|
|
753
|
+
while (userData.length >= USER_PACKET_SIZE) {
|
|
754
|
+
// Decode user data and add to the users array
|
|
755
|
+
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
756
|
+
users.push(user);
|
|
757
|
+
this._users.set(user.user_id, user);
|
|
758
|
+
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
759
|
+
}
|
|
760
|
+
// Return the list of users
|
|
761
|
+
return { data: users };
|
|
762
|
+
}
|
|
763
|
+
catch (err) {
|
|
764
|
+
// Log the error for debugging
|
|
765
|
+
console.error('Error getting users:', err);
|
|
766
|
+
// Re-throw the error to be handled by the caller
|
|
767
|
+
throw err;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
771
|
+
let user;
|
|
772
|
+
try {
|
|
773
|
+
user = await this.getUserByUserId(user_id);
|
|
774
|
+
}
|
|
775
|
+
catch (err) {
|
|
776
|
+
if (err.message.includes("user_id not exists")) {
|
|
777
|
+
user.uid = Math.max(...Array.from(this._users.values()).map(usr => usr.uid)) + 1;
|
|
778
|
+
this._users.set(user_id, user);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
try {
|
|
782
|
+
// Validate input parameters
|
|
783
|
+
if (user_id.length > 9 ||
|
|
784
|
+
name.length > 24 ||
|
|
785
|
+
password.length > 8 ||
|
|
786
|
+
typeof role !== 'number' ||
|
|
787
|
+
cardno.toString().length > 10) {
|
|
788
|
+
throw new Error('Invalid input parameters');
|
|
789
|
+
}
|
|
790
|
+
// Allocate and initialize the buffer
|
|
791
|
+
const commandBuffer = Buffer.alloc(72);
|
|
792
|
+
// Fill the buffer with user data
|
|
793
|
+
commandBuffer.writeUInt16LE(user.uid, 0);
|
|
794
|
+
commandBuffer.writeUInt16LE(role, 2);
|
|
795
|
+
commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
|
|
796
|
+
commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
|
|
797
|
+
commandBuffer.writeUInt16LE(cardno, 35);
|
|
798
|
+
commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
|
|
799
|
+
commandBuffer.write(user_id.padEnd(9, '\0'), 48, 9); // Ensure userid is 9 bytes
|
|
800
|
+
// Send the command and return the result
|
|
801
|
+
const created = await this._zkTcp.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
|
|
802
|
+
return !!created;
|
|
803
|
+
}
|
|
804
|
+
catch (err) {
|
|
805
|
+
// Log error details for debugging
|
|
806
|
+
console.error('Error setting user:', err);
|
|
807
|
+
// Re-throw error for upstream handling
|
|
808
|
+
throw err;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
async DeleteUser(user_id) {
|
|
812
|
+
try {
|
|
813
|
+
const user = await this.getUserByUserId(user_id);
|
|
814
|
+
// Allocate and initialize the buffer
|
|
815
|
+
const commandBuffer = Buffer.alloc(72);
|
|
816
|
+
// Write UID to the buffer
|
|
817
|
+
commandBuffer.writeUInt16LE(user.uid, 0);
|
|
818
|
+
// Send the delete command and return the result
|
|
819
|
+
const deleted = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USER, commandBuffer);
|
|
820
|
+
return !!deleted;
|
|
821
|
+
}
|
|
822
|
+
catch (err) {
|
|
823
|
+
// Log error details for debugging
|
|
824
|
+
console.error('Error deleting user:', err);
|
|
825
|
+
// Re-throw error for upstream handling
|
|
826
|
+
throw err;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
async getTemplates(callbackInProcess = () => { }) {
|
|
830
|
+
let templates = [];
|
|
831
|
+
try {
|
|
832
|
+
if (this._zkTcp.socket) {
|
|
833
|
+
await this._zkTcp.freeData();
|
|
834
|
+
}
|
|
835
|
+
await this._zkTcp.getSizes();
|
|
836
|
+
if (this._zkTcp.fp_count == 0)
|
|
837
|
+
return { data: [] };
|
|
838
|
+
await this._zkTcp.disableDevice();
|
|
839
|
+
const resp = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
|
|
840
|
+
let templateData = resp.data.subarray(4);
|
|
841
|
+
let totalSize = resp.data.readUIntLE(0, 4);
|
|
842
|
+
while (totalSize) {
|
|
843
|
+
const buf = templateData.subarray(0, 6);
|
|
844
|
+
const size = buf.readUIntLE(0, 2);
|
|
845
|
+
const uid = buf.readUIntLE(2, 2);
|
|
846
|
+
const fid = buf.readUIntLE(4, 1);
|
|
847
|
+
const valid = buf.readUIntLE(5, 1);
|
|
848
|
+
// Force-copy bytes so we don't retain the entire big backing buffer
|
|
849
|
+
const tplBytes = Buffer.from(templateData.subarray(6, size));
|
|
850
|
+
templates.push(new Finger(uid, fid, valid, tplBytes));
|
|
851
|
+
templateData = templateData.subarray(size);
|
|
852
|
+
totalSize -= size;
|
|
853
|
+
}
|
|
854
|
+
return { data: templates };
|
|
855
|
+
}
|
|
856
|
+
catch (err) {
|
|
857
|
+
this._zkTcp.verbose && console.log("Error getting templates", err);
|
|
858
|
+
return { data: templates };
|
|
859
|
+
}
|
|
860
|
+
finally {
|
|
861
|
+
await this._zkTcp.freeData();
|
|
862
|
+
await this._zkTcp.enableDevice();
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
async DownloadFp(user_id, fid) {
|
|
866
|
+
try {
|
|
867
|
+
const user = await this.getUserByUserId(user_id);
|
|
868
|
+
if (0 > fid || fid > 9)
|
|
869
|
+
throw new Error('fid must be between 0 and 9');
|
|
870
|
+
// Allocate and initialize the buffer
|
|
871
|
+
const data = Buffer.alloc(3);
|
|
872
|
+
// Fill the buffer with user data
|
|
873
|
+
data.writeUInt16LE(user.uid, 0);
|
|
874
|
+
data.writeUIntLE(fid, 2, 1);
|
|
875
|
+
this._zkTcp.replyId++;
|
|
876
|
+
const packet = createTCPHeader(COMMANDS.CMD_USERTEMP_RRQ, this._zkTcp.sessionId, this._zkTcp.replyId, data);
|
|
877
|
+
let fingerSize = 0;
|
|
878
|
+
let fingerTemplate = Buffer.from([]);
|
|
879
|
+
return await new Promise((resolve, reject) => {
|
|
880
|
+
let timeout;
|
|
881
|
+
const cleanup = () => {
|
|
882
|
+
if (this._zkTcp.socket) {
|
|
883
|
+
this._zkTcp.socket.removeListener('data', receiveData);
|
|
884
|
+
}
|
|
885
|
+
if (timeout)
|
|
886
|
+
clearTimeout(timeout);
|
|
887
|
+
};
|
|
888
|
+
let timer = () => setTimeout(() => {
|
|
889
|
+
cleanup();
|
|
890
|
+
reject(new Error('Time Out, Could not retrieve data'));
|
|
891
|
+
}, this._zkTcp.timeout);
|
|
892
|
+
const receiveData = (data) => {
|
|
893
|
+
timeout = timer();
|
|
894
|
+
if (data.length === 0)
|
|
895
|
+
return;
|
|
896
|
+
try {
|
|
897
|
+
if (data.length == 0)
|
|
898
|
+
return;
|
|
899
|
+
const headers = decodeTCPHeader(data);
|
|
900
|
+
switch (headers.commandId) {
|
|
901
|
+
case DISCOVERED_CMD.FID_NOT_FOUND:
|
|
902
|
+
throw new Error('Could not retrieve data. maybe finger id not exists?');
|
|
903
|
+
case COMMANDS.CMD_PREPARE_DATA:
|
|
904
|
+
fingerSize = data.readUIntLE(16, 2);
|
|
905
|
+
break;
|
|
906
|
+
case COMMANDS.CMD_DATA:
|
|
907
|
+
// A single 'data' event might contain multiple TCP packets combined by the OS
|
|
908
|
+
// in this method, is possible to get CMD_DATA and CMD_ACK_OK in the same event,
|
|
909
|
+
// so It's important to split data received for remove CMD_ACK_OK headers
|
|
910
|
+
fingerTemplate = Buffer.concat([fingerTemplate, data.subarray(16, fingerSize + 10)]);
|
|
911
|
+
// @ts-ignore
|
|
912
|
+
resolve(fingerTemplate);
|
|
913
|
+
break;
|
|
914
|
+
case COMMANDS.CMD_ACK_OK:
|
|
915
|
+
cleanup();
|
|
916
|
+
// @ts-ignore
|
|
917
|
+
resolve(fingerTemplate);
|
|
918
|
+
return;
|
|
919
|
+
default:
|
|
920
|
+
// If it's not a recognized command but has data, it might be raw template data
|
|
921
|
+
if (headers.commandId > 2000 && headers.commandId < 3000) {
|
|
922
|
+
// Likely another ACK or system msg
|
|
923
|
+
}
|
|
924
|
+
else {
|
|
925
|
+
fingerTemplate = Buffer.concat([fingerTemplate, data]);
|
|
926
|
+
}
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
clearTimeout(timeout);
|
|
930
|
+
}
|
|
931
|
+
catch (e) {
|
|
932
|
+
cleanup();
|
|
933
|
+
reject(e);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
if (this._zkTcp.socket) {
|
|
937
|
+
this._zkTcp.socket.on('data', receiveData);
|
|
938
|
+
this._zkTcp.socket.write(packet, (err) => {
|
|
939
|
+
if (err) {
|
|
940
|
+
cleanup();
|
|
941
|
+
reject(err);
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
reject(new Error('Socket not initialized'));
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
catch (err) {
|
|
951
|
+
throw err;
|
|
952
|
+
}
|
|
953
|
+
finally {
|
|
954
|
+
await this._zkTcp.refreshData();
|
|
955
|
+
}
|
|
593
956
|
}
|
|
594
957
|
/**
|
|
595
|
-
*
|
|
596
|
-
* @
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
958
|
+
*
|
|
959
|
+
* @param user_id {string} user
|
|
960
|
+
* @param fingers {Finger[]} array of finger templates instances
|
|
961
|
+
* */
|
|
962
|
+
async saveTemplates(user_id, fingers = []) {
|
|
963
|
+
if (fingers.length > 9 || fingers.length == 0)
|
|
964
|
+
throw new Error("maximum finger length is 10 and can't be empty");
|
|
965
|
+
try {
|
|
966
|
+
await this._zkTcp.disableDevice();
|
|
967
|
+
// check users exists
|
|
968
|
+
const user = await this.getUserByUserId(user_id);
|
|
969
|
+
let fpack = Buffer.alloc(0);
|
|
970
|
+
let table = Buffer.alloc(0);
|
|
971
|
+
const fnum = 0x10;
|
|
972
|
+
let tstart = 0;
|
|
973
|
+
for (const finger of fingers) {
|
|
974
|
+
const tfp = finger.repackOnly();
|
|
975
|
+
const tableEntry = Buffer.alloc(11); // b=1, H=2, b=1, I=4 => 1+2+1+4=8? Wait, bHbI is 1+2+1+4=8 bytes
|
|
976
|
+
tableEntry.writeInt8(2, 0);
|
|
977
|
+
tableEntry.writeUInt16LE(user.uid, 1);
|
|
978
|
+
tableEntry.writeInt8(fnum + finger.fid, 3);
|
|
979
|
+
tableEntry.writeUInt32LE(tstart, 4);
|
|
980
|
+
table = Buffer.concat([table, tableEntry]);
|
|
981
|
+
tstart += tfp.length;
|
|
982
|
+
fpack = Buffer.concat([fpack, tfp]);
|
|
983
|
+
}
|
|
984
|
+
let upack;
|
|
985
|
+
if (this._zkTcp.userPacketSize === 28) {
|
|
986
|
+
upack = user.repack29();
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
upack = user.repack73();
|
|
990
|
+
}
|
|
991
|
+
const head = Buffer.alloc(12); // III = 3*4 bytes
|
|
992
|
+
head.writeUInt32LE(upack.length, 0);
|
|
993
|
+
head.writeUInt32LE(table.length, 4);
|
|
994
|
+
head.writeUInt32LE(fpack.length, 8);
|
|
995
|
+
const packet = Buffer.concat([head, upack, table, fpack]);
|
|
996
|
+
const bufferResponse = await this._zkTcp.sendWithBuffer(packet);
|
|
997
|
+
const command = 110;
|
|
998
|
+
const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
|
|
999
|
+
commandString.writeUInt32LE(12, 0);
|
|
1000
|
+
commandString.writeUInt16LE(0, 4);
|
|
1001
|
+
commandString.writeUInt16LE(8, 6);
|
|
1002
|
+
const cmdResponse = await this._zkTcp.executeCmd(command, commandString);
|
|
1003
|
+
if (this._zkTcp.verbose)
|
|
1004
|
+
console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
|
|
601
1005
|
}
|
|
602
|
-
|
|
603
|
-
|
|
1006
|
+
catch (error) {
|
|
1007
|
+
throw error;
|
|
1008
|
+
}
|
|
1009
|
+
finally {
|
|
1010
|
+
await this._zkTcp.refreshData();
|
|
1011
|
+
await this._zkTcp.enableDevice();
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
async deleteFinger(user_id, fid) {
|
|
1015
|
+
try {
|
|
1016
|
+
if (!this._users.has(user_id))
|
|
1017
|
+
throw new Error("user_id not exists");
|
|
1018
|
+
const user = await this.getUserByUserId(user_id);
|
|
1019
|
+
const buf = Buffer.alloc(4);
|
|
1020
|
+
buf.writeUInt16LE(user_id ? user.uid : 0, 0);
|
|
1021
|
+
buf.writeUint16LE(fid ? fid : 0, 2);
|
|
1022
|
+
const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USERTEMP, buf);
|
|
1023
|
+
return !!reply;
|
|
1024
|
+
}
|
|
1025
|
+
catch (error) {
|
|
1026
|
+
throw new Error("Can't save utemp");
|
|
1027
|
+
}
|
|
1028
|
+
finally {
|
|
1029
|
+
await this._zkTcp.refreshData();
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
async enrollInfo(user_id, tempId) {
|
|
1033
|
+
let done = false;
|
|
1034
|
+
try {
|
|
1035
|
+
const userBuf = Buffer.alloc(24);
|
|
1036
|
+
userBuf.write(user_id, 0, 24, 'ascii');
|
|
1037
|
+
let commandString = Buffer.concat([
|
|
1038
|
+
userBuf,
|
|
1039
|
+
Buffer.from([tempId, 1])
|
|
1040
|
+
]);
|
|
1041
|
+
const sendAckOk = async () => {
|
|
1042
|
+
try {
|
|
1043
|
+
const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this._zkTcp.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
|
|
1044
|
+
this._zkTcp.socket.write(buf);
|
|
1045
|
+
}
|
|
1046
|
+
catch (e) {
|
|
1047
|
+
throw new ZkError(e, COMMANDS.CMD_ACK_OK, this._zkTcp.ip);
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
const cancel = await this._zkTcp.cancelCapture();
|
|
1051
|
+
const cmdResponse = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
|
|
1052
|
+
this._zkTcp.timeout = 60000; // 60 seconds timeout
|
|
1053
|
+
let attempts = 3;
|
|
1054
|
+
while (attempts > 0) {
|
|
1055
|
+
if (this._zkTcp.verbose)
|
|
1056
|
+
console.log(`A:${attempts} esperando primer regevent`);
|
|
1057
|
+
let dataRecv = await this._zkTcp.readSocket(17);
|
|
1058
|
+
await sendAckOk();
|
|
1059
|
+
if (dataRecv.length > 16) {
|
|
1060
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1061
|
+
const res = padded.readUInt16LE(16);
|
|
1062
|
+
if (this._zkTcp.verbose)
|
|
1063
|
+
console.log(`res ${res}`);
|
|
1064
|
+
if (res === 0 || res === 6 || res === 4) {
|
|
1065
|
+
if (this._zkTcp.verbose)
|
|
1066
|
+
console.log("posible timeout o reg Fallido");
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (this._zkTcp.verbose)
|
|
1071
|
+
console.log(`A:${attempts} esperando 2do regevent`);
|
|
1072
|
+
dataRecv = await this._zkTcp.readSocket(17);
|
|
1073
|
+
await sendAckOk();
|
|
1074
|
+
if (this._zkTcp.verbose)
|
|
1075
|
+
console.log(dataRecv);
|
|
1076
|
+
if (dataRecv.length > 8) {
|
|
1077
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1078
|
+
const res = padded.readUInt16LE(16);
|
|
1079
|
+
if (this._zkTcp.verbose)
|
|
1080
|
+
console.log(`res ${res}`);
|
|
1081
|
+
if (res === 6 || res === 4) {
|
|
1082
|
+
if (this._zkTcp.verbose)
|
|
1083
|
+
console.log("posible timeout o reg Fallido");
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
else if (res === 0x64) {
|
|
1087
|
+
if (this._zkTcp.verbose)
|
|
1088
|
+
console.log("ok, continue?");
|
|
1089
|
+
attempts--;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (attempts === 0) {
|
|
1094
|
+
const dataRecv = await this._zkTcp.readSocket(17);
|
|
1095
|
+
await sendAckOk();
|
|
1096
|
+
if (this._zkTcp.verbose)
|
|
1097
|
+
console.log(dataRecv.toString('hex'));
|
|
1098
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1099
|
+
let res = padded.readUInt16LE(16);
|
|
1100
|
+
if (this._zkTcp.verbose)
|
|
1101
|
+
console.log(`res ${res}`);
|
|
1102
|
+
if (res === 5) {
|
|
1103
|
+
if (this._zkTcp.verbose)
|
|
1104
|
+
console.log("finger duplicate");
|
|
1105
|
+
}
|
|
1106
|
+
if (res === 6 || res === 4) {
|
|
1107
|
+
if (this._zkTcp.verbose)
|
|
1108
|
+
console.log("posible timeout");
|
|
1109
|
+
}
|
|
1110
|
+
if (res === 0) {
|
|
1111
|
+
const size = padded.readUInt16LE(10);
|
|
1112
|
+
const pos = padded.readUInt16LE(12);
|
|
1113
|
+
if (this._zkTcp.verbose)
|
|
1114
|
+
console.log(`enroll ok ${size} ${pos}`);
|
|
1115
|
+
done = true;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
//this.__sock.setTimeout(this.__timeout);
|
|
1119
|
+
await this._zkTcp.regEvent(0); // TODO: test
|
|
1120
|
+
return done;
|
|
1121
|
+
}
|
|
1122
|
+
catch (error) {
|
|
1123
|
+
throw error;
|
|
1124
|
+
}
|
|
1125
|
+
finally {
|
|
1126
|
+
await this._zkTcp.cancelCapture();
|
|
1127
|
+
await this.verify(user_id);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
async verify(user_id) {
|
|
1131
|
+
try {
|
|
1132
|
+
const user = await this.getUserByUserId(user_id);
|
|
1133
|
+
const command_string = Buffer.alloc(4);
|
|
1134
|
+
command_string.writeUInt32LE(user.uid, 0);
|
|
1135
|
+
const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTVERIFY, command_string);
|
|
1136
|
+
if (this._zkTcp.verbose)
|
|
1137
|
+
console.log(reply.readUInt16LE(0));
|
|
1138
|
+
return !!reply;
|
|
1139
|
+
}
|
|
1140
|
+
catch (error) {
|
|
1141
|
+
console.error(error);
|
|
1142
|
+
throw error;
|
|
604
1143
|
}
|
|
605
|
-
return this.err.message;
|
|
606
1144
|
}
|
|
607
1145
|
/**
|
|
608
|
-
*
|
|
609
|
-
* @
|
|
1146
|
+
* Upload a single fingerprint for a given user id
|
|
1147
|
+
* @param user_id {string} user id for customer
|
|
1148
|
+
* @param fingerTemplate {string} finger template in base64 string
|
|
1149
|
+
* @param fid {number} finger id is a number between 0 and 9
|
|
1150
|
+
* @param fp_valid {number} finger flag. e.g., valid=1, duress=3
|
|
610
1151
|
*/
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
1152
|
+
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
1153
|
+
try {
|
|
1154
|
+
const check_ACK_OK = (buf) => {
|
|
1155
|
+
let resp_cmd = initPacket.readUInt16LE(0);
|
|
1156
|
+
if (resp_cmd === COMMANDS.CMD_ACK_OK)
|
|
1157
|
+
return true;
|
|
1158
|
+
else
|
|
1159
|
+
throw new Error(`received unexpected command: ${resp_cmd}`);
|
|
1160
|
+
};
|
|
1161
|
+
const user = this._users.get(user_id);
|
|
1162
|
+
await this._zkTcp.disableDevice();
|
|
1163
|
+
const prep_struct = Buffer.alloc(4);
|
|
1164
|
+
const fingerBuffer = Buffer.from(fingerTemplate, 'base64');
|
|
1165
|
+
const fp_size = fingerBuffer.length;
|
|
1166
|
+
prep_struct.writeUInt16LE(fp_size, 0);
|
|
1167
|
+
const initPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_PREPARE_DATA, prep_struct);
|
|
1168
|
+
check_ACK_OK(initPacket);
|
|
1169
|
+
const fpPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_DATA, fingerBuffer);
|
|
1170
|
+
check_ACK_OK(fpPacket);
|
|
1171
|
+
const cheksumPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_CHECKSUM_BUFFER, '');
|
|
1172
|
+
check_ACK_OK(cheksumPacket);
|
|
1173
|
+
const checksum = cheksumPacket.readUInt32LE(8);
|
|
1174
|
+
const tmp_wreq = Buffer.alloc(6);
|
|
1175
|
+
tmp_wreq.writeUInt16LE(user.uid, 0);
|
|
1176
|
+
tmp_wreq.writeUIntLE(fid, 2, 1);
|
|
1177
|
+
tmp_wreq.writeUIntLE(fp_valid, 3, 1);
|
|
1178
|
+
tmp_wreq.writeUInt16LE(fp_size, 4);
|
|
1179
|
+
const tmp_wreqPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_TMP_WRITE, tmp_wreq);
|
|
1180
|
+
check_ACK_OK(tmp_wreqPacket);
|
|
1181
|
+
const freeData = await this._zkTcp.executeCmd(COMMANDS.CMD_FREE_DATA, '');
|
|
1182
|
+
return check_ACK_OK(freeData);
|
|
1183
|
+
}
|
|
1184
|
+
catch (err) {
|
|
1185
|
+
throw err;
|
|
1186
|
+
}
|
|
1187
|
+
finally {
|
|
1188
|
+
await this._zkTcp.refreshData();
|
|
1189
|
+
await this._zkTcp.enableDevice();
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
class TransactionService {
|
|
1195
|
+
_zkTcp;
|
|
1196
|
+
constructor(zkTcp) {
|
|
1197
|
+
this._zkTcp = zkTcp;
|
|
1198
|
+
}
|
|
1199
|
+
async getAttendances(callbackInProcess = () => { }) {
|
|
1200
|
+
try {
|
|
1201
|
+
// Free any existing buffer data to prepare for a new request
|
|
1202
|
+
if (this._zkTcp.socket) {
|
|
1203
|
+
await this._zkTcp.freeData();
|
|
1204
|
+
}
|
|
1205
|
+
// Request attendance logs and handle chunked data
|
|
1206
|
+
const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS, callbackInProcess);
|
|
1207
|
+
// Free buffer data after receiving the attendance logs
|
|
1208
|
+
if (this._zkTcp.socket) {
|
|
1209
|
+
await this._zkTcp.freeData();
|
|
1210
|
+
}
|
|
1211
|
+
// Constants for record processing
|
|
1212
|
+
const RECORD_PACKET_SIZE = 40;
|
|
1213
|
+
// Ensure data.data is a valid buffer
|
|
1214
|
+
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1215
|
+
throw new Error('Invalid data received');
|
|
1216
|
+
}
|
|
1217
|
+
// Process the record data
|
|
1218
|
+
let recordData = data.data.subarray(4); // Skip header
|
|
1219
|
+
const records = [];
|
|
1220
|
+
// Process each attendance record
|
|
1221
|
+
while (recordData.length >= RECORD_PACKET_SIZE) {
|
|
1222
|
+
const record = decodeRecordData40(recordData.subarray(0, RECORD_PACKET_SIZE));
|
|
1223
|
+
records.push({ ...record, ip: this._zkTcp.ip }); // Add IP address to each record
|
|
1224
|
+
recordData = recordData.subarray(RECORD_PACKET_SIZE); // Move to the next packet
|
|
1225
|
+
}
|
|
1226
|
+
// Return the list of attendance records
|
|
1227
|
+
return { data: records };
|
|
1228
|
+
}
|
|
1229
|
+
catch (err) {
|
|
1230
|
+
// Log and re-throw the error
|
|
1231
|
+
console.error('Error getting attendance records:', err);
|
|
1232
|
+
throw err; // Re-throw the error for handling by the caller
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
// Clears the attendance logs on the device
|
|
1236
|
+
async clearAttendanceLog() {
|
|
1237
|
+
try {
|
|
1238
|
+
// Execute the command to clear attendance logs
|
|
1239
|
+
await this._zkTcp.disableDevice();
|
|
1240
|
+
const buf = await this._zkTcp.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, '');
|
|
1241
|
+
await this._zkTcp.refreshData();
|
|
1242
|
+
await this._zkTcp.enableDevice();
|
|
1243
|
+
return !!buf;
|
|
1244
|
+
}
|
|
1245
|
+
catch (err) {
|
|
1246
|
+
// Log the error for debugging purposes
|
|
1247
|
+
console.error('Error clearing attendance log:', err);
|
|
1248
|
+
// Re-throw the error to be handled by the caller
|
|
1249
|
+
throw err;
|
|
1250
|
+
}
|
|
620
1251
|
}
|
|
621
1252
|
}
|
|
622
1253
|
|
|
@@ -652,6 +1283,8 @@ class ZTCP {
|
|
|
652
1283
|
verbose = false;
|
|
653
1284
|
packetNumber = 0;
|
|
654
1285
|
replyData = Buffer.from([]);
|
|
1286
|
+
_userService;
|
|
1287
|
+
_transactionService;
|
|
655
1288
|
constructor(ip, port, timeout, comm_key, verbose) {
|
|
656
1289
|
this.ip = ip;
|
|
657
1290
|
this.port = port;
|
|
@@ -659,6 +1292,8 @@ class ZTCP {
|
|
|
659
1292
|
this.replyId = 0;
|
|
660
1293
|
this.comm_key = comm_key;
|
|
661
1294
|
this.verbose = verbose;
|
|
1295
|
+
this._userService = new UserService(this);
|
|
1296
|
+
this._transactionService = new TransactionService(this);
|
|
662
1297
|
}
|
|
663
1298
|
createSocket(cbError, cbClose) {
|
|
664
1299
|
return new Promise((resolve, reject) => {
|
|
@@ -880,6 +1515,10 @@ class ZTCP {
|
|
|
880
1515
|
try {
|
|
881
1516
|
// Write the message to the socket and wait for a response
|
|
882
1517
|
const reply = await this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT);
|
|
1518
|
+
if (this.verbose) {
|
|
1519
|
+
let headers = decodeTCPHeader(reply);
|
|
1520
|
+
console.log('command: ', COMMANDS[headers.commandId], 'replyid: ', headers.replyId);
|
|
1521
|
+
}
|
|
883
1522
|
// Remove TCP header from the response
|
|
884
1523
|
const rReply = removeTcpHeader(reply);
|
|
885
1524
|
// Update sessionId for connection command responses
|
|
@@ -1029,89 +1668,14 @@ class ZTCP {
|
|
|
1029
1668
|
}
|
|
1030
1669
|
});
|
|
1031
1670
|
}
|
|
1032
|
-
/**
|
|
1033
|
-
* reject error when starting request data
|
|
1034
|
-
* @return {Record<string, User[] | Error>} when receiving requested data
|
|
1035
|
-
*/
|
|
1036
|
-
async getUsers() {
|
|
1037
|
-
try {
|
|
1038
|
-
// Free any existing buffer data to prepare for a new request
|
|
1039
|
-
if (this.socket) {
|
|
1040
|
-
await this.freeData();
|
|
1041
|
-
}
|
|
1042
|
-
// Request user data
|
|
1043
|
-
const data = await this.readWithBuffer(REQUEST_DATA.GET_USERS);
|
|
1044
|
-
// Free buffer data after receiving the data
|
|
1045
|
-
if (this.socket) {
|
|
1046
|
-
await this.freeData();
|
|
1047
|
-
}
|
|
1048
|
-
// Constants for user data processing
|
|
1049
|
-
const USER_PACKET_SIZE = 72;
|
|
1050
|
-
// Ensure data.data is a valid buffer
|
|
1051
|
-
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1052
|
-
throw new Error('Invalid data received');
|
|
1053
|
-
}
|
|
1054
|
-
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
1055
|
-
const users = [];
|
|
1056
|
-
// Process each user packet
|
|
1057
|
-
while (userData.length >= USER_PACKET_SIZE) {
|
|
1058
|
-
// Decode user data and add to the users array
|
|
1059
|
-
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
1060
|
-
users.push(user);
|
|
1061
|
-
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
1062
|
-
}
|
|
1063
|
-
// Return the list of users
|
|
1064
|
-
return { data: users };
|
|
1065
|
-
}
|
|
1066
|
-
catch (err) {
|
|
1067
|
-
// Log the error for debugging
|
|
1068
|
-
console.error('Error getting users:', err);
|
|
1069
|
-
// Re-throw the error to be handled by the caller
|
|
1070
|
-
throw err;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
1671
|
/**
|
|
1074
1672
|
*
|
|
1075
|
-
* @param {*}
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
try {
|
|
1082
|
-
// Free any existing buffer data to prepare for a new request
|
|
1083
|
-
if (this.socket) {
|
|
1084
|
-
await this.freeData();
|
|
1085
|
-
}
|
|
1086
|
-
// Request attendance logs and handle chunked data
|
|
1087
|
-
const data = await this.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS, callbackInProcess);
|
|
1088
|
-
// Free buffer data after receiving the attendance logs
|
|
1089
|
-
if (this.socket) {
|
|
1090
|
-
await this.freeData();
|
|
1091
|
-
}
|
|
1092
|
-
// Constants for record processing
|
|
1093
|
-
const RECORD_PACKET_SIZE = 40;
|
|
1094
|
-
// Ensure data.data is a valid buffer
|
|
1095
|
-
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1096
|
-
throw new Error('Invalid data received');
|
|
1097
|
-
}
|
|
1098
|
-
// Process the record data
|
|
1099
|
-
let recordData = data.data.subarray(4); // Skip header
|
|
1100
|
-
const records = [];
|
|
1101
|
-
// Process each attendance record
|
|
1102
|
-
while (recordData.length >= RECORD_PACKET_SIZE) {
|
|
1103
|
-
const record = decodeRecordData40(recordData.subarray(0, RECORD_PACKET_SIZE));
|
|
1104
|
-
records.push({ ...record, ip: this.ip }); // Add IP address to each record
|
|
1105
|
-
recordData = recordData.subarray(RECORD_PACKET_SIZE); // Move to the next packet
|
|
1106
|
-
}
|
|
1107
|
-
// Return the list of attendance records
|
|
1108
|
-
return { data: records };
|
|
1109
|
-
}
|
|
1110
|
-
catch (err) {
|
|
1111
|
-
// Log and re-throw the error
|
|
1112
|
-
console.error('Error getting attendance records:', err);
|
|
1113
|
-
throw err; // Re-throw the error for handling by the caller
|
|
1114
|
-
}
|
|
1673
|
+
* @param {*} callbackInProcess
|
|
1674
|
+
* reject error when starting request data
|
|
1675
|
+
* return { data: records, err: Error } when receiving requested data
|
|
1676
|
+
*/
|
|
1677
|
+
async getAttendances(callbackInProcess = () => { }) {
|
|
1678
|
+
return await this._transactionService.getAttendances(callbackInProcess);
|
|
1115
1679
|
}
|
|
1116
1680
|
async freeData() {
|
|
1117
1681
|
try {
|
|
@@ -1307,17 +1871,26 @@ class ZTCP {
|
|
|
1307
1871
|
}
|
|
1308
1872
|
async getSerialNumber() {
|
|
1309
1873
|
const keyword = '~SerialNumber';
|
|
1874
|
+
let serialNumber = '';
|
|
1875
|
+
let count = 10;
|
|
1310
1876
|
try {
|
|
1311
1877
|
// Execute the command to get serial number
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
.
|
|
1319
|
-
|
|
1320
|
-
|
|
1878
|
+
/**
|
|
1879
|
+
* @dev implemented a counter and a while loop because sometimes serial number parses wrong for some reason
|
|
1880
|
+
* */
|
|
1881
|
+
while (serialNumber.length !== 13 && count > 0) {
|
|
1882
|
+
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1883
|
+
// Extract and format the serial number from the response data
|
|
1884
|
+
const SN = data.slice(8) // Skip the first 8 bytes (header)
|
|
1885
|
+
.toString('utf-8') // Convert buffer to string
|
|
1886
|
+
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1887
|
+
.replace('=', '') // Remove sometines last number is a character equal to = or unknow character
|
|
1888
|
+
.replace(/\u0000/g, ''); // Remove null characters
|
|
1889
|
+
if (serialNumber.length !== 13 && this.verbose) {
|
|
1890
|
+
console.warn('Serial number length not equal to 13, check');
|
|
1891
|
+
}
|
|
1892
|
+
count--;
|
|
1893
|
+
serialNumber = SN;
|
|
1321
1894
|
}
|
|
1322
1895
|
return serialNumber;
|
|
1323
1896
|
}
|
|
@@ -1429,11 +2002,10 @@ class ZTCP {
|
|
|
1429
2002
|
// Execute the command to get the PIN information
|
|
1430
2003
|
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1431
2004
|
// Extract and format the PIN information from the response data
|
|
1432
|
-
// Remove null characters
|
|
1433
2005
|
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1434
2006
|
.toString('ascii') // Convert buffer to ASCII string
|
|
1435
2007
|
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1436
|
-
.replace(/\u0000/g, '');
|
|
2008
|
+
.replace(/\u0000/g, ''); // Remove null characters 0x00
|
|
1437
2009
|
}
|
|
1438
2010
|
catch (err) {
|
|
1439
2011
|
// Log the error for debugging
|
|
@@ -1485,7 +2057,9 @@ class ZTCP {
|
|
|
1485
2057
|
// Execute the command to get firmware information
|
|
1486
2058
|
const data = await this.executeCmd(1100, '');
|
|
1487
2059
|
// Extract and return the firmware version from the response data
|
|
1488
|
-
return data.slice(8)
|
|
2060
|
+
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2061
|
+
.toString('ascii') // convert to ASCII string
|
|
2062
|
+
.replace(/\u0000/g, ''); // remove x00
|
|
1489
2063
|
}
|
|
1490
2064
|
catch (err) {
|
|
1491
2065
|
// Log the error for debugging
|
|
@@ -1551,59 +2125,6 @@ class ZTCP {
|
|
|
1551
2125
|
throw err;
|
|
1552
2126
|
}
|
|
1553
2127
|
}
|
|
1554
|
-
async setUser(uid, userid, name, password, role = 0, cardno = 0) {
|
|
1555
|
-
try {
|
|
1556
|
-
// Validate input parameters
|
|
1557
|
-
if (uid <= 0 || uid > 3000 ||
|
|
1558
|
-
userid.length > 9 ||
|
|
1559
|
-
name.length > 24 ||
|
|
1560
|
-
password.length > 8 ||
|
|
1561
|
-
typeof role !== 'number' ||
|
|
1562
|
-
cardno.toString().length > 10) {
|
|
1563
|
-
throw new Error('Invalid input parameters');
|
|
1564
|
-
}
|
|
1565
|
-
// Allocate and initialize the buffer
|
|
1566
|
-
const commandBuffer = Buffer.alloc(72);
|
|
1567
|
-
// Fill the buffer with user data
|
|
1568
|
-
commandBuffer.writeUInt16LE(uid, 0);
|
|
1569
|
-
commandBuffer.writeUInt16LE(role, 2);
|
|
1570
|
-
commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
|
|
1571
|
-
commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
|
|
1572
|
-
commandBuffer.writeUInt16LE(cardno, 35);
|
|
1573
|
-
commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
|
|
1574
|
-
commandBuffer.write(userid.padEnd(9, '\0'), 48, 9); // Ensure userid is 9 bytes
|
|
1575
|
-
// Send the command and return the result
|
|
1576
|
-
const created = await this.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
|
|
1577
|
-
return !!created;
|
|
1578
|
-
}
|
|
1579
|
-
catch (err) {
|
|
1580
|
-
// Log error details for debugging
|
|
1581
|
-
console.error('Error setting user:', err);
|
|
1582
|
-
// Re-throw error for upstream handling
|
|
1583
|
-
throw err;
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
async deleteUser(uid) {
|
|
1587
|
-
try {
|
|
1588
|
-
// Validate input parameter
|
|
1589
|
-
if (uid <= 0 || uid > 3000) {
|
|
1590
|
-
throw new Error('Invalid UID: must be between 1 and 3000');
|
|
1591
|
-
}
|
|
1592
|
-
// Allocate and initialize the buffer
|
|
1593
|
-
const commandBuffer = Buffer.alloc(72);
|
|
1594
|
-
// Write UID to the buffer
|
|
1595
|
-
commandBuffer.writeUInt16LE(uid, 0);
|
|
1596
|
-
// Send the delete command and return the result
|
|
1597
|
-
const deleted = await this.executeCmd(COMMANDS.CMD_DELETE_USER, commandBuffer);
|
|
1598
|
-
return !!deleted;
|
|
1599
|
-
}
|
|
1600
|
-
catch (err) {
|
|
1601
|
-
// Log error details for debugging
|
|
1602
|
-
console.error('Error deleting user:', err);
|
|
1603
|
-
// Re-throw error for upstream handling
|
|
1604
|
-
throw err;
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
2128
|
async getAttendanceSize() {
|
|
1608
2129
|
try {
|
|
1609
2130
|
// Execute command to get free sizes
|
|
@@ -1620,22 +2141,27 @@ class ZTCP {
|
|
|
1620
2141
|
}
|
|
1621
2142
|
// Clears the attendance logs on the device
|
|
1622
2143
|
async clearAttendanceLog() {
|
|
1623
|
-
|
|
1624
|
-
// Execute the command to clear attendance logs
|
|
1625
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, '');
|
|
1626
|
-
}
|
|
1627
|
-
catch (err) {
|
|
1628
|
-
// Log the error for debugging purposes
|
|
1629
|
-
console.error('Error clearing attendance log:', err);
|
|
1630
|
-
// Re-throw the error to be handled by the caller
|
|
1631
|
-
throw err;
|
|
1632
|
-
}
|
|
2144
|
+
return await this._transactionService.clearAttendanceLog();
|
|
1633
2145
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
2146
|
+
/**
|
|
2147
|
+
* Clears all data on the device
|
|
2148
|
+
* @value 1 Attendance records
|
|
2149
|
+
* @value 2 Fingerprint templates
|
|
2150
|
+
* @value 3 None
|
|
2151
|
+
* @value 4 Operation records
|
|
2152
|
+
* @value 5 User information
|
|
2153
|
+
* @default 0 Delete all
|
|
2154
|
+
*/
|
|
2155
|
+
async clearData(value) {
|
|
1636
2156
|
try {
|
|
1637
2157
|
// Execute the command to clear all data
|
|
1638
|
-
|
|
2158
|
+
await this.disableDevice();
|
|
2159
|
+
if (!value)
|
|
2160
|
+
value = 3;
|
|
2161
|
+
const buf = await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, value.toString());
|
|
2162
|
+
await this.refreshData();
|
|
2163
|
+
await this.enableDevice();
|
|
2164
|
+
return !!buf;
|
|
1639
2165
|
}
|
|
1640
2166
|
catch (err) {
|
|
1641
2167
|
// Log the error for debugging purposes
|
|
@@ -1682,33 +2208,7 @@ class ZTCP {
|
|
|
1682
2208
|
* @returns {Record<string, Finger[]>}
|
|
1683
2209
|
*/
|
|
1684
2210
|
async getTemplates(callbackInProcess = () => { }) {
|
|
1685
|
-
|
|
1686
|
-
try {
|
|
1687
|
-
await this.getSizes();
|
|
1688
|
-
if (this.fp_count == 0)
|
|
1689
|
-
return { data: [] };
|
|
1690
|
-
await this.freeData();
|
|
1691
|
-
await this.disableDevice();
|
|
1692
|
-
const Buffer = await this.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
|
|
1693
|
-
let templateData = Buffer.data.subarray(4);
|
|
1694
|
-
let totalSize = Buffer.data.readUIntLE(0, 4);
|
|
1695
|
-
while (totalSize) {
|
|
1696
|
-
const buf = templateData.subarray(0, 6);
|
|
1697
|
-
const size = buf.readUIntLE(0, 2);
|
|
1698
|
-
templates.push(new Finger(buf.readUIntLE(2, 2), buf.readUIntLE(4, 1), buf.readUIntLE(5, 1), templateData.subarray(6, size)));
|
|
1699
|
-
templateData = templateData.subarray(size);
|
|
1700
|
-
totalSize -= size;
|
|
1701
|
-
}
|
|
1702
|
-
return { data: templates };
|
|
1703
|
-
}
|
|
1704
|
-
catch (err) {
|
|
1705
|
-
this.verbose && console.log("Error getting templates", err);
|
|
1706
|
-
return { data: templates };
|
|
1707
|
-
}
|
|
1708
|
-
finally {
|
|
1709
|
-
await this.enableDevice();
|
|
1710
|
-
await this.freeData();
|
|
1711
|
-
}
|
|
2211
|
+
return await this._userService.getTemplates(callbackInProcess);
|
|
1712
2212
|
}
|
|
1713
2213
|
/**
|
|
1714
2214
|
* Return size
|
|
@@ -1784,197 +2284,6 @@ class ZTCP {
|
|
|
1784
2284
|
throw new ZkError(e, COMMANDS.CMD_DATA, this.ip);
|
|
1785
2285
|
}
|
|
1786
2286
|
}
|
|
1787
|
-
/**
|
|
1788
|
-
* save user and template
|
|
1789
|
-
*
|
|
1790
|
-
* @param {User | number | string} user - User class object | uid | user_id
|
|
1791
|
-
* @param {Finger[]} fingers - Array of finger class. `0 <= index <= 9`
|
|
1792
|
-
*/
|
|
1793
|
-
async saveUserTemplate(user, fingers = []) {
|
|
1794
|
-
if (fingers.length > 9 || fingers.length == 0)
|
|
1795
|
-
throw new Error("maximum finger length is 10 and can't be empty");
|
|
1796
|
-
try {
|
|
1797
|
-
await this.disableDevice();
|
|
1798
|
-
const users = await this.getUsers();
|
|
1799
|
-
//check users exists
|
|
1800
|
-
if (!users.data.some(u => u.uid == user.uid || +u.user_id == +user.user_id))
|
|
1801
|
-
throw new Error("error validating user input");
|
|
1802
|
-
if (!(user instanceof User)) {
|
|
1803
|
-
let tusers = users.data.filter(x => x.uid === +user.uid);
|
|
1804
|
-
if (tusers.length === 1) {
|
|
1805
|
-
user = tusers[0];
|
|
1806
|
-
}
|
|
1807
|
-
else {
|
|
1808
|
-
tusers = users.data.filter(x => x.user_id === String(user));
|
|
1809
|
-
if (tusers.length === 1) {
|
|
1810
|
-
user = tusers[0];
|
|
1811
|
-
}
|
|
1812
|
-
else {
|
|
1813
|
-
throw new Error("Can't find user");
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
if (fingers instanceof Finger) {
|
|
1818
|
-
fingers = [fingers];
|
|
1819
|
-
}
|
|
1820
|
-
let fpack = Buffer.alloc(0);
|
|
1821
|
-
let table = Buffer.alloc(0);
|
|
1822
|
-
const fnum = 0x10;
|
|
1823
|
-
let tstart = 0;
|
|
1824
|
-
for (const finger of fingers) {
|
|
1825
|
-
const tfp = finger.repackOnly();
|
|
1826
|
-
const tableEntry = Buffer.alloc(11); // b=1, H=2, b=1, I=4 => 1+2+1+4=8? Wait, bHbI is 1+2+1+4=8 bytes
|
|
1827
|
-
tableEntry.writeInt8(2, 0);
|
|
1828
|
-
tableEntry.writeUInt16LE(user.uid, 1);
|
|
1829
|
-
tableEntry.writeInt8(fnum + finger.fid, 3);
|
|
1830
|
-
tableEntry.writeUInt32LE(tstart, 4);
|
|
1831
|
-
table = Buffer.concat([table, tableEntry]);
|
|
1832
|
-
tstart += tfp.length;
|
|
1833
|
-
fpack = Buffer.concat([fpack, tfp]);
|
|
1834
|
-
}
|
|
1835
|
-
let upack;
|
|
1836
|
-
if (this.userPacketSize === 28) {
|
|
1837
|
-
upack = user.repack29();
|
|
1838
|
-
}
|
|
1839
|
-
else {
|
|
1840
|
-
upack = user.repack73();
|
|
1841
|
-
}
|
|
1842
|
-
const head = Buffer.alloc(12); // III = 3*4 bytes
|
|
1843
|
-
head.writeUInt32LE(upack.length, 0);
|
|
1844
|
-
head.writeUInt32LE(table.length, 4);
|
|
1845
|
-
head.writeUInt32LE(fpack.length, 8);
|
|
1846
|
-
const packet = Buffer.concat([head, upack, table, fpack]);
|
|
1847
|
-
const bufferResponse = await this.sendWithBuffer(packet);
|
|
1848
|
-
const command = 110;
|
|
1849
|
-
const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
|
|
1850
|
-
commandString.writeUInt32LE(12, 0);
|
|
1851
|
-
commandString.writeUInt16LE(0, 4);
|
|
1852
|
-
commandString.writeUInt16LE(8, 6);
|
|
1853
|
-
const cmdResponse = await this.executeCmd(command, commandString);
|
|
1854
|
-
if (this.verbose)
|
|
1855
|
-
console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
|
|
1856
|
-
}
|
|
1857
|
-
catch (error) {
|
|
1858
|
-
throw error;
|
|
1859
|
-
}
|
|
1860
|
-
finally {
|
|
1861
|
-
await this.refreshData();
|
|
1862
|
-
await this.enableDevice();
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
async deleteFinger(uid, fid) {
|
|
1866
|
-
try {
|
|
1867
|
-
const buf = Buffer.alloc(4);
|
|
1868
|
-
buf.writeUInt16LE(uid, 0);
|
|
1869
|
-
buf.writeUint16LE(fid, 2);
|
|
1870
|
-
const reply = await this.executeCmd(COMMANDS.CMD_DELETE_USERTEMP, buf);
|
|
1871
|
-
return !!reply;
|
|
1872
|
-
}
|
|
1873
|
-
catch (error) {
|
|
1874
|
-
throw new Error("Can't save utemp");
|
|
1875
|
-
}
|
|
1876
|
-
finally {
|
|
1877
|
-
await this.refreshData();
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
async enrollUser(uid, tempId, userId = '') {
|
|
1881
|
-
let done = false;
|
|
1882
|
-
try {
|
|
1883
|
-
//validate user exists
|
|
1884
|
-
const users = await this.getUsers();
|
|
1885
|
-
const filteredUsers = users.data.filter(x => x.uid === uid);
|
|
1886
|
-
if (filteredUsers.length >= 1) {
|
|
1887
|
-
userId = filteredUsers[0].user_id;
|
|
1888
|
-
}
|
|
1889
|
-
else {
|
|
1890
|
-
throw new Error("user not found");
|
|
1891
|
-
}
|
|
1892
|
-
const userBuf = Buffer.alloc(24);
|
|
1893
|
-
userBuf.write(userId.toString(), 0, 24, 'ascii');
|
|
1894
|
-
let commandString = Buffer.concat([
|
|
1895
|
-
userBuf,
|
|
1896
|
-
Buffer.from([tempId, 1])
|
|
1897
|
-
]);
|
|
1898
|
-
const cancel = await this.cancelCapture();
|
|
1899
|
-
const cmdResponse = await this.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
|
|
1900
|
-
this.timeout = 60000; // 60 seconds timeout
|
|
1901
|
-
let attempts = 3;
|
|
1902
|
-
while (attempts > 0) {
|
|
1903
|
-
if (this.verbose)
|
|
1904
|
-
console.log(`A:${attempts} esperando primer regevent`);
|
|
1905
|
-
let dataRecv = await this.readSocket(17);
|
|
1906
|
-
await this.ackOk();
|
|
1907
|
-
if (dataRecv.length > 16) {
|
|
1908
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1909
|
-
const res = padded.readUInt16LE(16);
|
|
1910
|
-
if (this.verbose)
|
|
1911
|
-
console.log(`res ${res}`);
|
|
1912
|
-
if (res === 0 || res === 6 || res === 4) {
|
|
1913
|
-
if (this.verbose)
|
|
1914
|
-
console.log("posible timeout o reg Fallido");
|
|
1915
|
-
break;
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
if (this.verbose)
|
|
1919
|
-
console.log(`A:${attempts} esperando 2do regevent`);
|
|
1920
|
-
dataRecv = await this.readSocket(17);
|
|
1921
|
-
await this.ackOk();
|
|
1922
|
-
if (this.verbose)
|
|
1923
|
-
console.log(dataRecv);
|
|
1924
|
-
if (dataRecv.length > 8) {
|
|
1925
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1926
|
-
const res = padded.readUInt16LE(16);
|
|
1927
|
-
if (this.verbose)
|
|
1928
|
-
console.log(`res ${res}`);
|
|
1929
|
-
if (res === 6 || res === 4) {
|
|
1930
|
-
if (this.verbose)
|
|
1931
|
-
console.log("posible timeout o reg Fallido");
|
|
1932
|
-
break;
|
|
1933
|
-
}
|
|
1934
|
-
else if (res === 0x64) {
|
|
1935
|
-
if (this.verbose)
|
|
1936
|
-
console.log("ok, continue?");
|
|
1937
|
-
attempts--;
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
if (attempts === 0) {
|
|
1942
|
-
const dataRecv = await this.readSocket(17);
|
|
1943
|
-
await this.ackOk();
|
|
1944
|
-
if (this.verbose)
|
|
1945
|
-
console.log(dataRecv.toString('hex'));
|
|
1946
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1947
|
-
let res = padded.readUInt16LE(16);
|
|
1948
|
-
if (this.verbose)
|
|
1949
|
-
console.log(`res ${res}`);
|
|
1950
|
-
if (res === 5) {
|
|
1951
|
-
if (this.verbose)
|
|
1952
|
-
console.log("finger duplicate");
|
|
1953
|
-
}
|
|
1954
|
-
if (res === 6 || res === 4) {
|
|
1955
|
-
if (this.verbose)
|
|
1956
|
-
console.log("posible timeout");
|
|
1957
|
-
}
|
|
1958
|
-
if (res === 0) {
|
|
1959
|
-
const size = padded.readUInt16LE(10);
|
|
1960
|
-
const pos = padded.readUInt16LE(12);
|
|
1961
|
-
if (this.verbose)
|
|
1962
|
-
console.log(`enroll ok ${size} ${pos}`);
|
|
1963
|
-
done = true;
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
//this.__sock.setTimeout(this.__timeout);
|
|
1967
|
-
await this.regEvent(0); // TODO: test
|
|
1968
|
-
return done;
|
|
1969
|
-
}
|
|
1970
|
-
catch (error) {
|
|
1971
|
-
throw error;
|
|
1972
|
-
}
|
|
1973
|
-
finally {
|
|
1974
|
-
await this.cancelCapture();
|
|
1975
|
-
await this.verifyUser(undefined);
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
2287
|
async readSocket(length, cb = null) {
|
|
1979
2288
|
let replyBufer = Buffer.from([]);
|
|
1980
2289
|
let totalPackets = 0;
|
|
@@ -2024,15 +2333,6 @@ class ZTCP {
|
|
|
2024
2333
|
throw new ZkError(e, COMMANDS.CMD_REG_EVENT, this.ip);
|
|
2025
2334
|
}
|
|
2026
2335
|
}
|
|
2027
|
-
async ackOk() {
|
|
2028
|
-
try {
|
|
2029
|
-
const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
|
|
2030
|
-
this.socket.write(buf);
|
|
2031
|
-
}
|
|
2032
|
-
catch (e) {
|
|
2033
|
-
throw new ZkError(e, COMMANDS.CMD_ACK_OK, this.ip);
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
2336
|
async cancelCapture() {
|
|
2037
2337
|
try {
|
|
2038
2338
|
const reply = await this.executeCmd(COMMANDS.CMD_CANCELCAPTURE, '');
|
|
@@ -2042,22 +2342,6 @@ class ZTCP {
|
|
|
2042
2342
|
throw new ZkError(e, COMMANDS.CMD_CANCELCAPTURE, this.ip);
|
|
2043
2343
|
}
|
|
2044
2344
|
}
|
|
2045
|
-
async verifyUser(uid) {
|
|
2046
|
-
try {
|
|
2047
|
-
let command_string = '';
|
|
2048
|
-
if (uid) {
|
|
2049
|
-
command_string = Buffer.alloc(4);
|
|
2050
|
-
command_string.writeUInt32LE(uid, 0);
|
|
2051
|
-
}
|
|
2052
|
-
const reply = await this.executeCmd(COMMANDS.CMD_STARTVERIFY, command_string);
|
|
2053
|
-
if (this.verbose)
|
|
2054
|
-
console.log(reply.readUInt16LE(0));
|
|
2055
|
-
return !!reply;
|
|
2056
|
-
}
|
|
2057
|
-
catch (error) {
|
|
2058
|
-
console.error(error);
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
2345
|
async restartDevice() {
|
|
2062
2346
|
try {
|
|
2063
2347
|
await this.executeCmd(COMMANDS.CMD_RESTART, '');
|
|
@@ -2442,7 +2726,7 @@ class ZUDP {
|
|
|
2442
2726
|
}
|
|
2443
2727
|
async clearAttendanceLog() {
|
|
2444
2728
|
try {
|
|
2445
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, Buffer.alloc(0));
|
|
2729
|
+
return !!await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, Buffer.alloc(0));
|
|
2446
2730
|
}
|
|
2447
2731
|
catch (err) {
|
|
2448
2732
|
console.error('Error clearing attendance log:', err);
|
|
@@ -2451,7 +2735,7 @@ class ZUDP {
|
|
|
2451
2735
|
}
|
|
2452
2736
|
async clearData() {
|
|
2453
2737
|
try {
|
|
2454
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, Buffer.alloc(0));
|
|
2738
|
+
return !!await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, Buffer.alloc(0));
|
|
2455
2739
|
}
|
|
2456
2740
|
catch (err) {
|
|
2457
2741
|
console.error('Error clearing data:', err);
|
|
@@ -2642,7 +2926,7 @@ class Zklib {
|
|
|
2642
2926
|
}
|
|
2643
2927
|
}
|
|
2644
2928
|
async getUsers() {
|
|
2645
|
-
return this.functionWrapper(() => this.ztcp.getUsers(), () => this.zudp.getUsers(), 'GET_USERS');
|
|
2929
|
+
return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(), 'GET_USERS');
|
|
2646
2930
|
}
|
|
2647
2931
|
async getTime() {
|
|
2648
2932
|
return this.functionWrapper(() => this.ztcp.getTime(), () => this.zudp.getTime(), 'GET_TIME');
|
|
@@ -2692,11 +2976,22 @@ class Zklib {
|
|
|
2692
2976
|
async getFirmware() {
|
|
2693
2977
|
return this.functionWrapper(() => this.ztcp.getFirmware(), async () => { throw new Error('UDP get firmware not supported'); }, 'GET_FIRMWARE');
|
|
2694
2978
|
}
|
|
2695
|
-
|
|
2696
|
-
|
|
2979
|
+
/** Update or create a user if user id/pin not exists
|
|
2980
|
+
* @param user_id {string} user id/pin for customer
|
|
2981
|
+
* @param name {string} user name
|
|
2982
|
+
* @param password {string} user password
|
|
2983
|
+
* @param role {number} role/privilege id number
|
|
2984
|
+
* @param cardno {number} card number/id
|
|
2985
|
+
*/
|
|
2986
|
+
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
2987
|
+
return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => { throw new Error('UDP set user not supported'); }, 'SET_USER');
|
|
2697
2988
|
}
|
|
2698
|
-
|
|
2699
|
-
|
|
2989
|
+
/**
|
|
2990
|
+
* Delete user by a given user id/pin
|
|
2991
|
+
* @param user_id {string}
|
|
2992
|
+
*/
|
|
2993
|
+
async deleteUser(user_id) {
|
|
2994
|
+
return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => { throw new Error('UDP delete user not supported'); }, 'DELETE_USER');
|
|
2700
2995
|
}
|
|
2701
2996
|
async getAttendanceSize() {
|
|
2702
2997
|
return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => { throw new Error('UDP get attendance size not supported'); }, 'GET_ATTENDANCE_SIZE');
|
|
@@ -2710,25 +3005,55 @@ class Zklib {
|
|
|
2710
3005
|
async getTemplates() {
|
|
2711
3006
|
return this.functionWrapper(() => this.ztcp.getTemplates(), async () => { throw new Error('UDP get templates not supported'); }, 'GET_TEMPLATES');
|
|
2712
3007
|
}
|
|
2713
|
-
|
|
2714
|
-
|
|
3008
|
+
/**
|
|
3009
|
+
* Get a user template for a given user id/pin and finger id
|
|
3010
|
+
* @param user_id {string} user id/pin
|
|
3011
|
+
* @param fid {number} finger index
|
|
3012
|
+
*/
|
|
3013
|
+
async getUserTemplate(user_id, fid) {
|
|
3014
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.DownloadFp(user_id, fid), async () => { throw new Error('UDP get user template not implemented'); }, 'GET_USER_TEMPLATE');
|
|
3015
|
+
}
|
|
3016
|
+
/**
|
|
3017
|
+
* Upload a single fingerprint for a given user id
|
|
3018
|
+
* @param user_id {string} user id/pin for customer
|
|
3019
|
+
* @param fingerTemplate {string} finger template in base64 string
|
|
3020
|
+
* @param fid {number} finger id is a number between 0 and 9
|
|
3021
|
+
* @param fp_valid {number} finger flag. e.g., valid=1, duress=3
|
|
3022
|
+
*/
|
|
3023
|
+
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
3024
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid), async () => { throw new Error('UDP get user template not implemented'); }, 'UPLOAD_USER_TEMPLATE');
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
3027
|
+
* save user and template
|
|
3028
|
+
*
|
|
3029
|
+
* @param {string} user_id - user id for customer
|
|
3030
|
+
* @param {Finger[]} fingers - Array of finger class
|
|
3031
|
+
*/
|
|
3032
|
+
async saveUserTemplate(user_id, fingers = []) {
|
|
3033
|
+
return await this.functionWrapper(async () => await this.ztcp._userService.saveTemplates(user_id, fingers), async () => { throw new Error('UDP save user template not supported'); }, 'SAVE_USER_TEMPLATE');
|
|
2715
3034
|
}
|
|
2716
|
-
|
|
3035
|
+
/**
|
|
3036
|
+
* Delete a single finger template by user id and finger index
|
|
3037
|
+
* @param user_id {string} user id/pin for customer
|
|
3038
|
+
* @param fid {number} finger index
|
|
3039
|
+
*/
|
|
3040
|
+
async deleteFinger(user_id, fid) {
|
|
2717
3041
|
if (fid > 9 || 0 > fid)
|
|
2718
3042
|
throw new Error("fid params out of index");
|
|
2719
|
-
|
|
2720
|
-
throw new Error("fid params out of index");
|
|
2721
|
-
return this.functionWrapper(() => this.ztcp.deleteFinger(uid, fid), async () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
|
|
3043
|
+
return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
|
|
2722
3044
|
}
|
|
2723
|
-
|
|
3045
|
+
/**
|
|
3046
|
+
* Start to enroll a finger template
|
|
3047
|
+
* @param user_id {string} user id/pin for customer
|
|
3048
|
+
* @param temp_id {number} finger index
|
|
3049
|
+
*/
|
|
3050
|
+
async enrollUser(user_id, temp_id) {
|
|
2724
3051
|
if (temp_id < 0 || temp_id > 9)
|
|
2725
3052
|
throw new Error("temp_id out of range 0-9");
|
|
2726
|
-
|
|
2727
|
-
throw new Error("uid out of range 1-3000");
|
|
2728
|
-
return this.functionWrapper(() => this.ztcp.enrollUser(uid, temp_id, user_id), async () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
|
|
3053
|
+
return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
|
|
2729
3054
|
}
|
|
2730
|
-
async verifyUser(
|
|
2731
|
-
return this.functionWrapper(() => this.ztcp.
|
|
3055
|
+
async verifyUser(user_id) {
|
|
3056
|
+
return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => { throw new Error('UDP verify user not supported'); }, 'VERIFY_USER');
|
|
2732
3057
|
}
|
|
2733
3058
|
async restartDevice() {
|
|
2734
3059
|
return this.functionWrapper(() => this.ztcp.restartDevice(), async () => { throw new Error('UDP restart device not supported'); }, 'RESTART_DEVICE');
|