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.cjs.js
CHANGED
|
@@ -26,99 +26,190 @@ var dgram__namespace = /*#__PURE__*/_interopNamespaceDefault(dgram);
|
|
|
26
26
|
var COMMANDS;
|
|
27
27
|
(function (COMMANDS) {
|
|
28
28
|
COMMANDS[COMMANDS["CMD_ACK_DATA"] = 2002] = "CMD_ACK_DATA";
|
|
29
|
+
/** There was an error when processing the request.*/
|
|
29
30
|
COMMANDS[COMMANDS["CMD_ACK_ERROR"] = 2001] = "CMD_ACK_ERROR";
|
|
30
31
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_CMD"] = 65533] = "CMD_ACK_ERROR_CMD";
|
|
31
32
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_DATA"] = 65531] = "CMD_ACK_ERROR_DATA";
|
|
32
33
|
COMMANDS[COMMANDS["CMD_ACK_ERROR_INIT"] = 65532] = "CMD_ACK_ERROR_INIT";
|
|
34
|
+
/** [0xD0, 0x07] The request was processed sucessfully. */
|
|
33
35
|
COMMANDS[COMMANDS["CMD_ACK_OK"] = 2000] = "CMD_ACK_OK";
|
|
34
36
|
COMMANDS[COMMANDS["CMD_ACK_REPEAT"] = 2004] = "CMD_ACK_REPEAT";
|
|
35
37
|
COMMANDS[COMMANDS["CMD_ACK_RETRY"] = 2003] = "CMD_ACK_RETRY";
|
|
38
|
+
/** [0xD5, 0x07] Connection not authorized. */
|
|
36
39
|
COMMANDS[COMMANDS["CMD_ACK_UNAUTH"] = 2005] = "CMD_ACK_UNAUTH";
|
|
40
|
+
/** Received unknown command. */
|
|
37
41
|
COMMANDS[COMMANDS["CMD_ACK_UNKNOWN"] = 65535] = "CMD_ACK_UNKNOWN";
|
|
42
|
+
/** Request attendance log. */
|
|
38
43
|
COMMANDS[COMMANDS["CMD_ATTLOG_RRQ"] = 13] = "CMD_ATTLOG_RRQ";
|
|
44
|
+
/** [0x4E, 0x04] Request to begin session using commkey. */
|
|
39
45
|
COMMANDS[COMMANDS["CMD_AUTH"] = 1102] = "CMD_AUTH";
|
|
46
|
+
/** Disable normal authentication of users. */
|
|
40
47
|
COMMANDS[COMMANDS["CMD_CANCELCAPTURE"] = 62] = "CMD_CANCELCAPTURE";
|
|
48
|
+
/** Capture fingerprint picture. */
|
|
41
49
|
COMMANDS[COMMANDS["CMD_CAPTUREFINGER"] = 1009] = "CMD_CAPTUREFINGER";
|
|
50
|
+
/** Capture the entire image. */
|
|
42
51
|
COMMANDS[COMMANDS["CMD_CAPTUREIMAGE"] = 1012] = "CMD_CAPTUREIMAGE";
|
|
52
|
+
/** Change transmission speed. */
|
|
43
53
|
COMMANDS[COMMANDS["CMD_CHANGE_SPEED"] = 1101] = "CMD_CHANGE_SPEED";
|
|
54
|
+
/** [0x77, 0x00] Get checksum of machine's buffer. */
|
|
44
55
|
COMMANDS[COMMANDS["CMD_CHECKSUM_BUFFER"] = 119] = "CMD_CHECKSUM_BUFFER";
|
|
56
|
+
/** Restore access control to default. */
|
|
45
57
|
COMMANDS[COMMANDS["CMD_CLEAR_ACC"] = 32] = "CMD_CLEAR_ACC";
|
|
58
|
+
/** Clears admins privileges. */
|
|
46
59
|
COMMANDS[COMMANDS["CMD_CLEAR_ADMIN"] = 20] = "CMD_CLEAR_ADMIN";
|
|
60
|
+
/** Delete attendance record. */
|
|
47
61
|
COMMANDS[COMMANDS["CMD_CLEAR_ATTLOG"] = 15] = "CMD_CLEAR_ATTLOG";
|
|
62
|
+
/** Delete data. */
|
|
48
63
|
COMMANDS[COMMANDS["CMD_CLEAR_DATA"] = 14] = "CMD_CLEAR_DATA";
|
|
64
|
+
/** Clear screen captions. */
|
|
49
65
|
COMMANDS[COMMANDS["CMD_CLEAR_LCD"] = 67] = "CMD_CLEAR_LCD";
|
|
66
|
+
/** Delete operations log. */
|
|
50
67
|
COMMANDS[COMMANDS["CMD_CLEAR_OPLOG"] = 33] = "CMD_CLEAR_OPLOG";
|
|
68
|
+
/** [0xE8, 0x03] Begin connection. */
|
|
51
69
|
COMMANDS[COMMANDS["CMD_CONNECT"] = 1000] = "CMD_CONNECT";
|
|
70
|
+
/** [0xDD, 0x05] Data packet. */
|
|
52
71
|
COMMANDS[COMMANDS["CMD_DATA"] = 1501] = "CMD_DATA";
|
|
72
|
+
/** Indicates that it is ready to receive data. */
|
|
53
73
|
COMMANDS[COMMANDS["CMD_DATA_RDY"] = 1504] = "CMD_DATA_RDY";
|
|
74
|
+
/** Read/Write a large data set. */
|
|
54
75
|
COMMANDS[COMMANDS["CMD_DATA_WRRQ"] = 1503] = "CMD_DATA_WRRQ";
|
|
76
|
+
/** Read saved data. */
|
|
55
77
|
COMMANDS[COMMANDS["CMD_DB_RRQ"] = 7] = "CMD_DB_RRQ";
|
|
78
|
+
/** Deletes fingerprint template. */
|
|
56
79
|
COMMANDS[COMMANDS["CMD_DEL_FPTMP"] = 134] = "CMD_DEL_FPTMP";
|
|
80
|
+
/** Delete short message. */
|
|
57
81
|
COMMANDS[COMMANDS["CMD_DELETE_SMS"] = 72] = "CMD_DELETE_SMS";
|
|
82
|
+
/** Delete user short message. */
|
|
58
83
|
COMMANDS[COMMANDS["CMD_DELETE_UDATA"] = 74] = "CMD_DELETE_UDATA";
|
|
84
|
+
/** Delete user. */
|
|
59
85
|
COMMANDS[COMMANDS["CMD_DELETE_USER"] = 18] = "CMD_DELETE_USER";
|
|
86
|
+
/** Delete user fingerprint template. */
|
|
60
87
|
COMMANDS[COMMANDS["CMD_DELETE_USERTEMP"] = 19] = "CMD_DELETE_USERTEMP";
|
|
88
|
+
/** Disables fingerprint, rfid reader and keyboard. */
|
|
61
89
|
COMMANDS[COMMANDS["CMD_DISABLEDEVICE"] = 1003] = "CMD_DISABLEDEVICE";
|
|
90
|
+
/** Get door state. */
|
|
62
91
|
COMMANDS[COMMANDS["CMD_DOORSTATE_RRQ"] = 75] = "CMD_DOORSTATE_RRQ";
|
|
92
|
+
/** Clear Mifare card. */
|
|
63
93
|
COMMANDS[COMMANDS["CMD_EMPTY_MIFARE"] = 78] = "CMD_EMPTY_MIFARE";
|
|
94
|
+
/** Enables the ":" in screen clock. */
|
|
64
95
|
COMMANDS[COMMANDS["CMD_ENABLE_CLOCK"] = 57] = "CMD_ENABLE_CLOCK";
|
|
96
|
+
/** Change machine state to "normal work". */
|
|
65
97
|
COMMANDS[COMMANDS["CMD_ENABLEDEVICE"] = 1002] = "CMD_ENABLEDEVICE";
|
|
98
|
+
/** [0xE9, 0x03] Disconnect. */
|
|
66
99
|
COMMANDS[COMMANDS["CMD_EXIT"] = 1001] = "CMD_EXIT";
|
|
100
|
+
/** [0xDE, 0x05] Release buffer used for data transmission. */
|
|
67
101
|
COMMANDS[COMMANDS["CMD_FREE_DATA"] = 1502] = "CMD_FREE_DATA";
|
|
102
|
+
/** Request machine status (remaining space). */
|
|
68
103
|
COMMANDS[COMMANDS["CMD_GET_FREE_SIZES"] = 50] = "CMD_GET_FREE_SIZES";
|
|
104
|
+
/** Request max size for users id. */
|
|
69
105
|
COMMANDS[COMMANDS["CMD_GET_PINWIDTH"] = 69] = "CMD_GET_PINWIDTH";
|
|
106
|
+
/** Request machine time. */
|
|
70
107
|
COMMANDS[COMMANDS["CMD_GET_TIME"] = 201] = "CMD_GET_TIME";
|
|
71
108
|
COMMANDS[COMMANDS["CMD_GET_USERTEMP"] = 88] = "CMD_GET_USERTEMP";
|
|
109
|
+
/** Request the firmware edition. */
|
|
72
110
|
COMMANDS[COMMANDS["CMD_GET_VERSION"] = 1100] = "CMD_GET_VERSION";
|
|
111
|
+
/** Get group timezone. */
|
|
73
112
|
COMMANDS[COMMANDS["CMD_GRPTZ_RRQ"] = 25] = "CMD_GRPTZ_RRQ";
|
|
113
|
+
/** Set group timezone. */
|
|
74
114
|
COMMANDS[COMMANDS["CMD_GRPTZ_WRQ"] = 26] = "CMD_GRPTZ_WRQ";
|
|
115
|
+
/** Read operations log. */
|
|
75
116
|
COMMANDS[COMMANDS["CMD_OPLOG_RRQ"] = 34] = "CMD_OPLOG_RRQ";
|
|
117
|
+
/** Read configuration value of the machine. */
|
|
76
118
|
COMMANDS[COMMANDS["CMD_OPTIONS_RRQ"] = 11] = "CMD_OPTIONS_RRQ";
|
|
119
|
+
/** Change configuration value of the machine. */
|
|
77
120
|
COMMANDS[COMMANDS["CMD_OPTIONS_WRQ"] = 12] = "CMD_OPTIONS_WRQ";
|
|
121
|
+
/** Shut-down machine. */
|
|
78
122
|
COMMANDS[COMMANDS["CMD_POWEROFF"] = 1005] = "CMD_POWEROFF";
|
|
123
|
+
/** [0xDC, 0x05] Prepare for data transmission. */
|
|
79
124
|
COMMANDS[COMMANDS["CMD_PREPARE_DATA"] = 1500] = "CMD_PREPARE_DATA";
|
|
125
|
+
/** [0xF5, 0x03] Refresh the machine stored data. */
|
|
80
126
|
COMMANDS[COMMANDS["CMD_REFRESHDATA"] = 1013] = "CMD_REFRESHDATA";
|
|
127
|
+
/** Refresh the configuration parameters. */
|
|
81
128
|
COMMANDS[COMMANDS["CMD_REFRESHOPTION"] = 1014] = "CMD_REFRESHOPTION";
|
|
129
|
+
/** Realtime events. */
|
|
82
130
|
COMMANDS[COMMANDS["CMD_REG_EVENT"] = 500] = "CMD_REG_EVENT";
|
|
131
|
+
/** Restart machine. */
|
|
83
132
|
COMMANDS[COMMANDS["CMD_RESTART"] = 1004] = "CMD_RESTART";
|
|
133
|
+
/** Change machine state to "awaken". */
|
|
84
134
|
COMMANDS[COMMANDS["CMD_RESUME"] = 1007] = "CMD_RESUME";
|
|
135
|
+
/** Set machine time. */
|
|
85
136
|
COMMANDS[COMMANDS["CMD_SET_TIME"] = 202] = "CMD_SET_TIME";
|
|
137
|
+
/** Change machine state to "idle". */
|
|
86
138
|
COMMANDS[COMMANDS["CMD_SLEEP"] = 1006] = "CMD_SLEEP";
|
|
139
|
+
/** Download short message. */
|
|
87
140
|
COMMANDS[COMMANDS["CMD_SMS_RRQ"] = 71] = "CMD_SMS_RRQ";
|
|
141
|
+
/** Upload short message. */
|
|
88
142
|
COMMANDS[COMMANDS["CMD_SMS_WRQ"] = 70] = "CMD_SMS_WRQ";
|
|
143
|
+
/** Start enroll procedure. */
|
|
89
144
|
COMMANDS[COMMANDS["CMD_STARTENROLL"] = 61] = "CMD_STARTENROLL";
|
|
145
|
+
/** Set the machine to authentication state. */
|
|
90
146
|
COMMANDS[COMMANDS["CMD_STARTVERIFY"] = 60] = "CMD_STARTVERIFY";
|
|
147
|
+
/** Query state. */
|
|
91
148
|
COMMANDS[COMMANDS["CMD_STATE_RRQ"] = 64] = "CMD_STATE_RRQ";
|
|
149
|
+
/** Test if fingerprint exists. */
|
|
92
150
|
COMMANDS[COMMANDS["CMD_TEST_TEMP"] = 1011] = "CMD_TEST_TEMP";
|
|
151
|
+
/** Test voice. */
|
|
93
152
|
COMMANDS[COMMANDS["CMD_TESTVOICE"] = 1017] = "CMD_TESTVOICE";
|
|
153
|
+
/** [0x77, 0x00] Transfer fp template from buffer. */
|
|
94
154
|
COMMANDS[COMMANDS["CMD_TMP_WRITE"] = 87] = "CMD_TMP_WRITE";
|
|
155
|
+
/** Get device timezones. */
|
|
95
156
|
COMMANDS[COMMANDS["CMD_TZ_RRQ"] = 27] = "CMD_TZ_RRQ";
|
|
157
|
+
/** Set device timezones. */
|
|
96
158
|
COMMANDS[COMMANDS["CMD_TZ_WRQ"] = 28] = "CMD_TZ_WRQ";
|
|
159
|
+
/** Set user short message. */
|
|
97
160
|
COMMANDS[COMMANDS["CMD_UDATA_WRQ"] = 73] = "CMD_UDATA_WRQ";
|
|
161
|
+
/** Get group combination to unlock. */
|
|
98
162
|
COMMANDS[COMMANDS["CMD_ULG_RRQ"] = 29] = "CMD_ULG_RRQ";
|
|
163
|
+
/** Set group combination to unlock. */
|
|
99
164
|
COMMANDS[COMMANDS["CMD_ULG_WRQ"] = 30] = "CMD_ULG_WRQ";
|
|
165
|
+
/** Unlock door for a specified amount of time. */
|
|
100
166
|
COMMANDS[COMMANDS["CMD_UNLOCK"] = 31] = "CMD_UNLOCK";
|
|
167
|
+
/** Upload user data. */
|
|
101
168
|
COMMANDS[COMMANDS["CMD_USER_WRQ"] = 8] = "CMD_USER_WRQ";
|
|
169
|
+
/** Read user group. */
|
|
102
170
|
COMMANDS[COMMANDS["CMD_USERGRP_RRQ"] = 21] = "CMD_USERGRP_RRQ";
|
|
171
|
+
/** Set user group. */
|
|
103
172
|
COMMANDS[COMMANDS["CMD_USERGRP_WRQ"] = 22] = "CMD_USERGRP_WRQ";
|
|
173
|
+
/** [0x09, 0x00] Read user fingerprint template. */
|
|
104
174
|
COMMANDS[COMMANDS["CMD_USERTEMP_RRQ"] = 9] = "CMD_USERTEMP_RRQ";
|
|
175
|
+
/** Upload user fingerprint template. */
|
|
105
176
|
COMMANDS[COMMANDS["CMD_USERTEMP_WRQ"] = 10] = "CMD_USERTEMP_WRQ";
|
|
177
|
+
/** Get user timezones. */
|
|
106
178
|
COMMANDS[COMMANDS["CMD_USERTZ_RRQ"] = 23] = "CMD_USERTZ_RRQ";
|
|
179
|
+
/** Set the user timezones. */
|
|
107
180
|
COMMANDS[COMMANDS["CMD_USERTZ_WRQ"] = 24] = "CMD_USERTZ_WRQ";
|
|
181
|
+
/** Read verification style of a given user. */
|
|
108
182
|
COMMANDS[COMMANDS["CMD_VERIFY_RRQ"] = 80] = "CMD_VERIFY_RRQ";
|
|
183
|
+
/** Change verification style of a given user. */
|
|
109
184
|
COMMANDS[COMMANDS["CMD_VERIFY_WRQ"] = 79] = "CMD_VERIFY_WRQ";
|
|
185
|
+
/** Prints chars to the device screen. */
|
|
110
186
|
COMMANDS[COMMANDS["CMD_WRITE_LCD"] = 66] = "CMD_WRITE_LCD";
|
|
187
|
+
/** Write data to Mifare card. */
|
|
111
188
|
COMMANDS[COMMANDS["CMD_WRITE_MIFARE"] = 76] = "CMD_WRITE_MIFARE";
|
|
189
|
+
/** Triggered alarm. */
|
|
112
190
|
COMMANDS[COMMANDS["EF_ALARM"] = 512] = "EF_ALARM";
|
|
191
|
+
/** Attendance entry. */
|
|
113
192
|
COMMANDS[COMMANDS["EF_ATTLOG"] = 1] = "EF_ATTLOG";
|
|
193
|
+
/** Pressed keyboard key. */
|
|
114
194
|
COMMANDS[COMMANDS["EF_BUTTON"] = 16] = "EF_BUTTON";
|
|
195
|
+
/** Upload user data. */
|
|
115
196
|
COMMANDS[COMMANDS["EF_ENROLLFINGER"] = 8] = "EF_ENROLLFINGER";
|
|
197
|
+
/** Enrolled user. */
|
|
116
198
|
COMMANDS[COMMANDS["EF_ENROLLUSER"] = 4] = "EF_ENROLLUSER";
|
|
199
|
+
/** Pressed finger. */
|
|
117
200
|
COMMANDS[COMMANDS["EF_FINGER"] = 2] = "EF_FINGER";
|
|
201
|
+
/** Fingerprint score in enroll procedure. */
|
|
118
202
|
COMMANDS[COMMANDS["EF_FPFTR"] = 256] = "EF_FPFTR";
|
|
203
|
+
/** Restore access control to default. */
|
|
119
204
|
COMMANDS[COMMANDS["EF_UNLOCK"] = 32] = "EF_UNLOCK";
|
|
205
|
+
/** Registered user placed finger. */
|
|
120
206
|
COMMANDS[COMMANDS["EF_VERIFY"] = 128] = "EF_VERIFY";
|
|
121
207
|
})(COMMANDS || (COMMANDS = {}));
|
|
208
|
+
var DISCOVERED_CMD;
|
|
209
|
+
(function (DISCOVERED_CMD) {
|
|
210
|
+
/** Returned when the Finger id not exists in the user uid, when attempting to download single finger template */
|
|
211
|
+
DISCOVERED_CMD[DISCOVERED_CMD["FID_NOT_FOUND"] = 4993] = "FID_NOT_FOUND";
|
|
212
|
+
})(DISCOVERED_CMD || (DISCOVERED_CMD = {}));
|
|
122
213
|
var Constants;
|
|
123
214
|
(function (Constants) {
|
|
124
215
|
Constants[Constants["USHRT_MAX"] = 65535] = "USHRT_MAX";
|
|
@@ -127,6 +218,7 @@ var Constants;
|
|
|
127
218
|
Constants[Constants["MACHINE_PREPARE_DATA_2"] = 32130] = "MACHINE_PREPARE_DATA_2";
|
|
128
219
|
})(Constants || (Constants = {}));
|
|
129
220
|
const REQUEST_DATA = {
|
|
221
|
+
START_TAG: Buffer.from([0x50, 0x50, 0x82, 0x7d]),
|
|
130
222
|
DISABLE_DEVICE: Buffer.from([0, 0, 0, 0]),
|
|
131
223
|
GET_REAL_TIME_EVENT: Buffer.from([0x01, 0x00, 0x00, 0x00]),
|
|
132
224
|
GET_ATTENDANCE_LOGS: Buffer.from([0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
|
@@ -274,18 +366,23 @@ class User {
|
|
|
274
366
|
}
|
|
275
367
|
|
|
276
368
|
class Attendance {
|
|
369
|
+
/** Internal serial number for the user */
|
|
277
370
|
sn;
|
|
371
|
+
/** User ID/Pin stored as a string */
|
|
278
372
|
user_id;
|
|
279
|
-
|
|
373
|
+
/** Verification type */
|
|
280
374
|
type;
|
|
375
|
+
/** Time of the attendance event */
|
|
376
|
+
record_time;
|
|
377
|
+
/** Verify state */
|
|
281
378
|
state;
|
|
282
379
|
ip;
|
|
283
|
-
constructor(sn, user_id,
|
|
380
|
+
constructor(sn, user_id, type, record_time, state) {
|
|
284
381
|
this.sn = sn;
|
|
285
382
|
this.user_id = user_id;
|
|
383
|
+
this.type = type || undefined;
|
|
286
384
|
this.record_time = record_time;
|
|
287
|
-
this.
|
|
288
|
-
this.state = state;
|
|
385
|
+
this.state = state || undefined;
|
|
289
386
|
}
|
|
290
387
|
}
|
|
291
388
|
|
|
@@ -329,17 +426,7 @@ const createUDPHeader = (command, sessionId, replyId, data) => {
|
|
|
329
426
|
return buf;
|
|
330
427
|
};
|
|
331
428
|
const createTCPHeader = (command, sessionId, replyId, data) => {
|
|
332
|
-
const
|
|
333
|
-
const buf = Buffer.alloc(8 + dataBuffer.length);
|
|
334
|
-
buf.writeUInt16LE(command, 0);
|
|
335
|
-
buf.writeUInt16LE(0, 2);
|
|
336
|
-
buf.writeUInt16LE(sessionId, 4);
|
|
337
|
-
buf.writeUInt16LE(replyId, 6);
|
|
338
|
-
dataBuffer.copy(buf, 8);
|
|
339
|
-
const chksum2 = createChkSum(buf);
|
|
340
|
-
buf.writeUInt16LE(chksum2, 2);
|
|
341
|
-
replyId = (replyId + 1) % Constants.USHRT_MAX;
|
|
342
|
-
buf.writeUInt16LE(replyId, 6);
|
|
429
|
+
const buf = createUDPHeader(command, sessionId, replyId, data);
|
|
343
430
|
const prefixBuf = Buffer.from([0x50, 0x50, 0x82, 0x7d, 0x13, 0x00, 0x00, 0x00]);
|
|
344
431
|
prefixBuf.writeUInt16LE(buf.length, 4);
|
|
345
432
|
return Buffer.concat([prefixBuf, buf]);
|
|
@@ -399,7 +486,7 @@ const decodeRecordData40 = (recordData) => {
|
|
|
399
486
|
.slice(2, 2 + 9)
|
|
400
487
|
.toString('ascii')
|
|
401
488
|
.split('\0')
|
|
402
|
-
.shift() || '',
|
|
489
|
+
.shift() || '', recordData.readUIntLE(26, 1), parseTimeToDate(recordData.readUInt32LE(27)), recordData.readUIntLE(31, 1));
|
|
403
490
|
};
|
|
404
491
|
const decodeRecordData16 = (recordData) => {
|
|
405
492
|
return {
|
|
@@ -515,6 +602,59 @@ const authKey = (comKey, sessionId) => {
|
|
|
515
602
|
return Array.from(response);
|
|
516
603
|
};
|
|
517
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Error types for device communication
|
|
607
|
+
*/
|
|
608
|
+
const ERROR_TYPES = {
|
|
609
|
+
ECONNRESET: 'ECONNRESET',
|
|
610
|
+
ECONNREFUSED: 'ECONNREFUSED'};
|
|
611
|
+
/**
|
|
612
|
+
* Custom error class for device communication errors
|
|
613
|
+
*/
|
|
614
|
+
class ZkError {
|
|
615
|
+
err;
|
|
616
|
+
ip;
|
|
617
|
+
command;
|
|
618
|
+
/**
|
|
619
|
+
* Creates a new ZkError instance
|
|
620
|
+
* @param err The error object
|
|
621
|
+
* @param command The command that caused the error
|
|
622
|
+
* @param ip The IP address of the device
|
|
623
|
+
*/
|
|
624
|
+
constructor(err, command, ip) {
|
|
625
|
+
this.err = err;
|
|
626
|
+
this.ip = ip;
|
|
627
|
+
this.command = command;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Gets a user-friendly error message
|
|
631
|
+
* @returns A formatted error message
|
|
632
|
+
*/
|
|
633
|
+
toast() {
|
|
634
|
+
if (this.err.code === ERROR_TYPES.ECONNRESET) {
|
|
635
|
+
return 'Another device is connecting to the device so the connection is interrupted';
|
|
636
|
+
}
|
|
637
|
+
else if (this.err.code === ERROR_TYPES.ECONNREFUSED) {
|
|
638
|
+
return 'IP of the device is refused';
|
|
639
|
+
}
|
|
640
|
+
return this.err.message;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Gets detailed error information
|
|
644
|
+
* @returns An object containing error details
|
|
645
|
+
*/
|
|
646
|
+
getError() {
|
|
647
|
+
return {
|
|
648
|
+
err: {
|
|
649
|
+
message: this.err.message,
|
|
650
|
+
code: this.err.code
|
|
651
|
+
},
|
|
652
|
+
ip: this.ip,
|
|
653
|
+
command: this.command
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
518
658
|
/**
|
|
519
659
|
* Represents a fingerprint template with associated metadata
|
|
520
660
|
*/
|
|
@@ -588,56 +728,547 @@ class Finger {
|
|
|
588
728
|
}
|
|
589
729
|
}
|
|
590
730
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
731
|
+
class UserService {
|
|
732
|
+
_zkTcp;
|
|
733
|
+
_users;
|
|
734
|
+
constructor(zkTcp) {
|
|
735
|
+
this._zkTcp = zkTcp;
|
|
736
|
+
}
|
|
737
|
+
async getUserByUserId(user_id) {
|
|
738
|
+
if (!this._users) {
|
|
739
|
+
await this.getUsers();
|
|
740
|
+
}
|
|
741
|
+
if (this._users.has(String(user_id))) {
|
|
742
|
+
return this._users.get(String(user_id));
|
|
743
|
+
}
|
|
744
|
+
else
|
|
745
|
+
throw new Error("user_id not exists");
|
|
746
|
+
}
|
|
747
|
+
async getUsers() {
|
|
748
|
+
try {
|
|
749
|
+
// Free any existing buffer data to prepare for a new request
|
|
750
|
+
if (this._users) {
|
|
751
|
+
return { data: Array.from(this._users.values()) };
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
this._users = new Map([]);
|
|
755
|
+
}
|
|
756
|
+
if (this._zkTcp.socket) {
|
|
757
|
+
await this._zkTcp.freeData();
|
|
758
|
+
}
|
|
759
|
+
// Request user data
|
|
760
|
+
const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_USERS);
|
|
761
|
+
// Free buffer data after receiving the data
|
|
762
|
+
if (this._zkTcp.socket) {
|
|
763
|
+
await this._zkTcp.freeData();
|
|
764
|
+
}
|
|
765
|
+
// Constants for user data processing
|
|
766
|
+
const USER_PACKET_SIZE = 72;
|
|
767
|
+
// Ensure data.data is a valid buffer
|
|
768
|
+
if (!data.data || !(data.data instanceof Buffer)) {
|
|
769
|
+
throw new Error('Invalid data received');
|
|
770
|
+
}
|
|
771
|
+
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
772
|
+
const users = [];
|
|
773
|
+
// Process each user packet
|
|
774
|
+
while (userData.length >= USER_PACKET_SIZE) {
|
|
775
|
+
// Decode user data and add to the users array
|
|
776
|
+
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
777
|
+
users.push(user);
|
|
778
|
+
this._users.set(user.user_id, user);
|
|
779
|
+
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
780
|
+
}
|
|
781
|
+
// Return the list of users
|
|
782
|
+
return { data: users };
|
|
783
|
+
}
|
|
784
|
+
catch (err) {
|
|
785
|
+
// Log the error for debugging
|
|
786
|
+
console.error('Error getting users:', err);
|
|
787
|
+
// Re-throw the error to be handled by the caller
|
|
788
|
+
throw err;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
792
|
+
let user;
|
|
793
|
+
try {
|
|
794
|
+
user = await this.getUserByUserId(user_id);
|
|
795
|
+
}
|
|
796
|
+
catch (err) {
|
|
797
|
+
if (err.message.includes("user_id not exists")) {
|
|
798
|
+
user.uid = Math.max(...Array.from(this._users.values()).map(usr => usr.uid)) + 1;
|
|
799
|
+
this._users.set(user_id, user);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
try {
|
|
803
|
+
// Validate input parameters
|
|
804
|
+
if (user_id.length > 9 ||
|
|
805
|
+
name.length > 24 ||
|
|
806
|
+
password.length > 8 ||
|
|
807
|
+
typeof role !== 'number' ||
|
|
808
|
+
cardno.toString().length > 10) {
|
|
809
|
+
throw new Error('Invalid input parameters');
|
|
810
|
+
}
|
|
811
|
+
// Allocate and initialize the buffer
|
|
812
|
+
const commandBuffer = Buffer.alloc(72);
|
|
813
|
+
// Fill the buffer with user data
|
|
814
|
+
commandBuffer.writeUInt16LE(user.uid, 0);
|
|
815
|
+
commandBuffer.writeUInt16LE(role, 2);
|
|
816
|
+
commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
|
|
817
|
+
commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
|
|
818
|
+
commandBuffer.writeUInt16LE(cardno, 35);
|
|
819
|
+
commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
|
|
820
|
+
commandBuffer.write(user_id.padEnd(9, '\0'), 48, 9); // Ensure userid is 9 bytes
|
|
821
|
+
// Send the command and return the result
|
|
822
|
+
const created = await this._zkTcp.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
|
|
823
|
+
return !!created;
|
|
824
|
+
}
|
|
825
|
+
catch (err) {
|
|
826
|
+
// Log error details for debugging
|
|
827
|
+
console.error('Error setting user:', err);
|
|
828
|
+
// Re-throw error for upstream handling
|
|
829
|
+
throw err;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async DeleteUser(user_id) {
|
|
833
|
+
try {
|
|
834
|
+
const user = await this.getUserByUserId(user_id);
|
|
835
|
+
// Allocate and initialize the buffer
|
|
836
|
+
const commandBuffer = Buffer.alloc(72);
|
|
837
|
+
// Write UID to the buffer
|
|
838
|
+
commandBuffer.writeUInt16LE(user.uid, 0);
|
|
839
|
+
// Send the delete command and return the result
|
|
840
|
+
const deleted = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USER, commandBuffer);
|
|
841
|
+
return !!deleted;
|
|
842
|
+
}
|
|
843
|
+
catch (err) {
|
|
844
|
+
// Log error details for debugging
|
|
845
|
+
console.error('Error deleting user:', err);
|
|
846
|
+
// Re-throw error for upstream handling
|
|
847
|
+
throw err;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async getTemplates(callbackInProcess = () => { }) {
|
|
851
|
+
let templates = [];
|
|
852
|
+
try {
|
|
853
|
+
if (this._zkTcp.socket) {
|
|
854
|
+
await this._zkTcp.freeData();
|
|
855
|
+
}
|
|
856
|
+
await this._zkTcp.getSizes();
|
|
857
|
+
if (this._zkTcp.fp_count == 0)
|
|
858
|
+
return { data: [] };
|
|
859
|
+
await this._zkTcp.disableDevice();
|
|
860
|
+
const resp = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
|
|
861
|
+
let templateData = resp.data.subarray(4);
|
|
862
|
+
let totalSize = resp.data.readUIntLE(0, 4);
|
|
863
|
+
while (totalSize) {
|
|
864
|
+
const buf = templateData.subarray(0, 6);
|
|
865
|
+
const size = buf.readUIntLE(0, 2);
|
|
866
|
+
const uid = buf.readUIntLE(2, 2);
|
|
867
|
+
const fid = buf.readUIntLE(4, 1);
|
|
868
|
+
const valid = buf.readUIntLE(5, 1);
|
|
869
|
+
// Force-copy bytes so we don't retain the entire big backing buffer
|
|
870
|
+
const tplBytes = Buffer.from(templateData.subarray(6, size));
|
|
871
|
+
templates.push(new Finger(uid, fid, valid, tplBytes));
|
|
872
|
+
templateData = templateData.subarray(size);
|
|
873
|
+
totalSize -= size;
|
|
874
|
+
}
|
|
875
|
+
return { data: templates };
|
|
876
|
+
}
|
|
877
|
+
catch (err) {
|
|
878
|
+
this._zkTcp.verbose && console.log("Error getting templates", err);
|
|
879
|
+
return { data: templates };
|
|
880
|
+
}
|
|
881
|
+
finally {
|
|
882
|
+
await this._zkTcp.freeData();
|
|
883
|
+
await this._zkTcp.enableDevice();
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
async DownloadFp(user_id, fid) {
|
|
887
|
+
try {
|
|
888
|
+
const user = await this.getUserByUserId(user_id);
|
|
889
|
+
if (0 > fid || fid > 9)
|
|
890
|
+
throw new Error('fid must be between 0 and 9');
|
|
891
|
+
// Allocate and initialize the buffer
|
|
892
|
+
const data = Buffer.alloc(3);
|
|
893
|
+
// Fill the buffer with user data
|
|
894
|
+
data.writeUInt16LE(user.uid, 0);
|
|
895
|
+
data.writeUIntLE(fid, 2, 1);
|
|
896
|
+
this._zkTcp.replyId++;
|
|
897
|
+
const packet = createTCPHeader(COMMANDS.CMD_USERTEMP_RRQ, this._zkTcp.sessionId, this._zkTcp.replyId, data);
|
|
898
|
+
let fingerSize = 0;
|
|
899
|
+
let fingerTemplate = Buffer.from([]);
|
|
900
|
+
return await new Promise((resolve, reject) => {
|
|
901
|
+
let timeout;
|
|
902
|
+
const cleanup = () => {
|
|
903
|
+
if (this._zkTcp.socket) {
|
|
904
|
+
this._zkTcp.socket.removeListener('data', receiveData);
|
|
905
|
+
}
|
|
906
|
+
if (timeout)
|
|
907
|
+
clearTimeout(timeout);
|
|
908
|
+
};
|
|
909
|
+
let timer = () => setTimeout(() => {
|
|
910
|
+
cleanup();
|
|
911
|
+
reject(new Error('Time Out, Could not retrieve data'));
|
|
912
|
+
}, this._zkTcp.timeout);
|
|
913
|
+
const receiveData = (data) => {
|
|
914
|
+
timeout = timer();
|
|
915
|
+
if (data.length === 0)
|
|
916
|
+
return;
|
|
917
|
+
try {
|
|
918
|
+
if (data.length == 0)
|
|
919
|
+
return;
|
|
920
|
+
const headers = decodeTCPHeader(data);
|
|
921
|
+
switch (headers.commandId) {
|
|
922
|
+
case DISCOVERED_CMD.FID_NOT_FOUND:
|
|
923
|
+
throw new Error('Could not retrieve data. maybe finger id not exists?');
|
|
924
|
+
case COMMANDS.CMD_PREPARE_DATA:
|
|
925
|
+
fingerSize = data.readUIntLE(16, 2);
|
|
926
|
+
break;
|
|
927
|
+
case COMMANDS.CMD_DATA:
|
|
928
|
+
// A single 'data' event might contain multiple TCP packets combined by the OS
|
|
929
|
+
// in this method, is possible to get CMD_DATA and CMD_ACK_OK in the same event,
|
|
930
|
+
// so It's important to split data received for remove CMD_ACK_OK headers
|
|
931
|
+
fingerTemplate = Buffer.concat([fingerTemplate, data.subarray(16, fingerSize + 10)]);
|
|
932
|
+
// @ts-ignore
|
|
933
|
+
resolve(fingerTemplate);
|
|
934
|
+
break;
|
|
935
|
+
case COMMANDS.CMD_ACK_OK:
|
|
936
|
+
cleanup();
|
|
937
|
+
// @ts-ignore
|
|
938
|
+
resolve(fingerTemplate);
|
|
939
|
+
return;
|
|
940
|
+
default:
|
|
941
|
+
// If it's not a recognized command but has data, it might be raw template data
|
|
942
|
+
if (headers.commandId > 2000 && headers.commandId < 3000) {
|
|
943
|
+
// Likely another ACK or system msg
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
fingerTemplate = Buffer.concat([fingerTemplate, data]);
|
|
947
|
+
}
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
clearTimeout(timeout);
|
|
951
|
+
}
|
|
952
|
+
catch (e) {
|
|
953
|
+
cleanup();
|
|
954
|
+
reject(e);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
if (this._zkTcp.socket) {
|
|
958
|
+
this._zkTcp.socket.on('data', receiveData);
|
|
959
|
+
this._zkTcp.socket.write(packet, (err) => {
|
|
960
|
+
if (err) {
|
|
961
|
+
cleanup();
|
|
962
|
+
reject(err);
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
reject(new Error('Socket not initialized'));
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
catch (err) {
|
|
972
|
+
throw err;
|
|
973
|
+
}
|
|
974
|
+
finally {
|
|
975
|
+
await this._zkTcp.refreshData();
|
|
976
|
+
}
|
|
614
977
|
}
|
|
615
978
|
/**
|
|
616
|
-
*
|
|
617
|
-
* @
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
979
|
+
*
|
|
980
|
+
* @param user_id {string} user
|
|
981
|
+
* @param fingers {Finger[]} array of finger templates instances
|
|
982
|
+
* */
|
|
983
|
+
async saveTemplates(user_id, fingers = []) {
|
|
984
|
+
if (fingers.length > 9 || fingers.length == 0)
|
|
985
|
+
throw new Error("maximum finger length is 10 and can't be empty");
|
|
986
|
+
try {
|
|
987
|
+
await this._zkTcp.disableDevice();
|
|
988
|
+
// check users exists
|
|
989
|
+
const user = await this.getUserByUserId(user_id);
|
|
990
|
+
let fpack = Buffer.alloc(0);
|
|
991
|
+
let table = Buffer.alloc(0);
|
|
992
|
+
const fnum = 0x10;
|
|
993
|
+
let tstart = 0;
|
|
994
|
+
for (const finger of fingers) {
|
|
995
|
+
const tfp = finger.repackOnly();
|
|
996
|
+
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
|
|
997
|
+
tableEntry.writeInt8(2, 0);
|
|
998
|
+
tableEntry.writeUInt16LE(user.uid, 1);
|
|
999
|
+
tableEntry.writeInt8(fnum + finger.fid, 3);
|
|
1000
|
+
tableEntry.writeUInt32LE(tstart, 4);
|
|
1001
|
+
table = Buffer.concat([table, tableEntry]);
|
|
1002
|
+
tstart += tfp.length;
|
|
1003
|
+
fpack = Buffer.concat([fpack, tfp]);
|
|
1004
|
+
}
|
|
1005
|
+
let upack;
|
|
1006
|
+
if (this._zkTcp.userPacketSize === 28) {
|
|
1007
|
+
upack = user.repack29();
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
upack = user.repack73();
|
|
1011
|
+
}
|
|
1012
|
+
const head = Buffer.alloc(12); // III = 3*4 bytes
|
|
1013
|
+
head.writeUInt32LE(upack.length, 0);
|
|
1014
|
+
head.writeUInt32LE(table.length, 4);
|
|
1015
|
+
head.writeUInt32LE(fpack.length, 8);
|
|
1016
|
+
const packet = Buffer.concat([head, upack, table, fpack]);
|
|
1017
|
+
const bufferResponse = await this._zkTcp.sendWithBuffer(packet);
|
|
1018
|
+
const command = 110;
|
|
1019
|
+
const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
|
|
1020
|
+
commandString.writeUInt32LE(12, 0);
|
|
1021
|
+
commandString.writeUInt16LE(0, 4);
|
|
1022
|
+
commandString.writeUInt16LE(8, 6);
|
|
1023
|
+
const cmdResponse = await this._zkTcp.executeCmd(command, commandString);
|
|
1024
|
+
if (this._zkTcp.verbose)
|
|
1025
|
+
console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
|
|
622
1026
|
}
|
|
623
|
-
|
|
624
|
-
|
|
1027
|
+
catch (error) {
|
|
1028
|
+
throw error;
|
|
1029
|
+
}
|
|
1030
|
+
finally {
|
|
1031
|
+
await this._zkTcp.refreshData();
|
|
1032
|
+
await this._zkTcp.enableDevice();
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
async deleteFinger(user_id, fid) {
|
|
1036
|
+
try {
|
|
1037
|
+
if (!this._users.has(user_id))
|
|
1038
|
+
throw new Error("user_id not exists");
|
|
1039
|
+
const user = await this.getUserByUserId(user_id);
|
|
1040
|
+
const buf = Buffer.alloc(4);
|
|
1041
|
+
buf.writeUInt16LE(user_id ? user.uid : 0, 0);
|
|
1042
|
+
buf.writeUint16LE(fid ? fid : 0, 2);
|
|
1043
|
+
const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_DELETE_USERTEMP, buf);
|
|
1044
|
+
return !!reply;
|
|
1045
|
+
}
|
|
1046
|
+
catch (error) {
|
|
1047
|
+
throw new Error("Can't save utemp");
|
|
1048
|
+
}
|
|
1049
|
+
finally {
|
|
1050
|
+
await this._zkTcp.refreshData();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
async enrollInfo(user_id, tempId) {
|
|
1054
|
+
let done = false;
|
|
1055
|
+
try {
|
|
1056
|
+
const userBuf = Buffer.alloc(24);
|
|
1057
|
+
userBuf.write(user_id, 0, 24, 'ascii');
|
|
1058
|
+
let commandString = Buffer.concat([
|
|
1059
|
+
userBuf,
|
|
1060
|
+
Buffer.from([tempId, 1])
|
|
1061
|
+
]);
|
|
1062
|
+
const sendAckOk = async () => {
|
|
1063
|
+
try {
|
|
1064
|
+
const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this._zkTcp.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
|
|
1065
|
+
this._zkTcp.socket.write(buf);
|
|
1066
|
+
}
|
|
1067
|
+
catch (e) {
|
|
1068
|
+
throw new ZkError(e, COMMANDS.CMD_ACK_OK, this._zkTcp.ip);
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
const cancel = await this._zkTcp.cancelCapture();
|
|
1072
|
+
const cmdResponse = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
|
|
1073
|
+
this._zkTcp.timeout = 60000; // 60 seconds timeout
|
|
1074
|
+
let attempts = 3;
|
|
1075
|
+
while (attempts > 0) {
|
|
1076
|
+
if (this._zkTcp.verbose)
|
|
1077
|
+
console.log(`A:${attempts} esperando primer regevent`);
|
|
1078
|
+
let dataRecv = await this._zkTcp.readSocket(17);
|
|
1079
|
+
await sendAckOk();
|
|
1080
|
+
if (dataRecv.length > 16) {
|
|
1081
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1082
|
+
const res = padded.readUInt16LE(16);
|
|
1083
|
+
if (this._zkTcp.verbose)
|
|
1084
|
+
console.log(`res ${res}`);
|
|
1085
|
+
if (res === 0 || res === 6 || res === 4) {
|
|
1086
|
+
if (this._zkTcp.verbose)
|
|
1087
|
+
console.log("posible timeout o reg Fallido");
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (this._zkTcp.verbose)
|
|
1092
|
+
console.log(`A:${attempts} esperando 2do regevent`);
|
|
1093
|
+
dataRecv = await this._zkTcp.readSocket(17);
|
|
1094
|
+
await sendAckOk();
|
|
1095
|
+
if (this._zkTcp.verbose)
|
|
1096
|
+
console.log(dataRecv);
|
|
1097
|
+
if (dataRecv.length > 8) {
|
|
1098
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1099
|
+
const res = padded.readUInt16LE(16);
|
|
1100
|
+
if (this._zkTcp.verbose)
|
|
1101
|
+
console.log(`res ${res}`);
|
|
1102
|
+
if (res === 6 || res === 4) {
|
|
1103
|
+
if (this._zkTcp.verbose)
|
|
1104
|
+
console.log("posible timeout o reg Fallido");
|
|
1105
|
+
break;
|
|
1106
|
+
}
|
|
1107
|
+
else if (res === 0x64) {
|
|
1108
|
+
if (this._zkTcp.verbose)
|
|
1109
|
+
console.log("ok, continue?");
|
|
1110
|
+
attempts--;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (attempts === 0) {
|
|
1115
|
+
const dataRecv = await this._zkTcp.readSocket(17);
|
|
1116
|
+
await sendAckOk();
|
|
1117
|
+
if (this._zkTcp.verbose)
|
|
1118
|
+
console.log(dataRecv.toString('hex'));
|
|
1119
|
+
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1120
|
+
let res = padded.readUInt16LE(16);
|
|
1121
|
+
if (this._zkTcp.verbose)
|
|
1122
|
+
console.log(`res ${res}`);
|
|
1123
|
+
if (res === 5) {
|
|
1124
|
+
if (this._zkTcp.verbose)
|
|
1125
|
+
console.log("finger duplicate");
|
|
1126
|
+
}
|
|
1127
|
+
if (res === 6 || res === 4) {
|
|
1128
|
+
if (this._zkTcp.verbose)
|
|
1129
|
+
console.log("posible timeout");
|
|
1130
|
+
}
|
|
1131
|
+
if (res === 0) {
|
|
1132
|
+
const size = padded.readUInt16LE(10);
|
|
1133
|
+
const pos = padded.readUInt16LE(12);
|
|
1134
|
+
if (this._zkTcp.verbose)
|
|
1135
|
+
console.log(`enroll ok ${size} ${pos}`);
|
|
1136
|
+
done = true;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
//this.__sock.setTimeout(this.__timeout);
|
|
1140
|
+
await this._zkTcp.regEvent(0); // TODO: test
|
|
1141
|
+
return done;
|
|
1142
|
+
}
|
|
1143
|
+
catch (error) {
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
1146
|
+
finally {
|
|
1147
|
+
await this._zkTcp.cancelCapture();
|
|
1148
|
+
await this.verify(user_id);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
async verify(user_id) {
|
|
1152
|
+
try {
|
|
1153
|
+
const user = await this.getUserByUserId(user_id);
|
|
1154
|
+
const command_string = Buffer.alloc(4);
|
|
1155
|
+
command_string.writeUInt32LE(user.uid, 0);
|
|
1156
|
+
const reply = await this._zkTcp.executeCmd(COMMANDS.CMD_STARTVERIFY, command_string);
|
|
1157
|
+
if (this._zkTcp.verbose)
|
|
1158
|
+
console.log(reply.readUInt16LE(0));
|
|
1159
|
+
return !!reply;
|
|
1160
|
+
}
|
|
1161
|
+
catch (error) {
|
|
1162
|
+
console.error(error);
|
|
1163
|
+
throw error;
|
|
625
1164
|
}
|
|
626
|
-
return this.err.message;
|
|
627
1165
|
}
|
|
628
1166
|
/**
|
|
629
|
-
*
|
|
630
|
-
* @
|
|
1167
|
+
* Upload a single fingerprint for a given user id
|
|
1168
|
+
* @param user_id {string} user id for customer
|
|
1169
|
+
* @param fingerTemplate {string} finger template in base64 string
|
|
1170
|
+
* @param fid {number} finger id is a number between 0 and 9
|
|
1171
|
+
* @param fp_valid {number} finger flag. e.g., valid=1, duress=3
|
|
631
1172
|
*/
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
1173
|
+
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
1174
|
+
try {
|
|
1175
|
+
const check_ACK_OK = (buf) => {
|
|
1176
|
+
let resp_cmd = initPacket.readUInt16LE(0);
|
|
1177
|
+
if (resp_cmd === COMMANDS.CMD_ACK_OK)
|
|
1178
|
+
return true;
|
|
1179
|
+
else
|
|
1180
|
+
throw new Error(`received unexpected command: ${resp_cmd}`);
|
|
1181
|
+
};
|
|
1182
|
+
const user = this._users.get(user_id);
|
|
1183
|
+
await this._zkTcp.disableDevice();
|
|
1184
|
+
const prep_struct = Buffer.alloc(4);
|
|
1185
|
+
const fingerBuffer = Buffer.from(fingerTemplate, 'base64');
|
|
1186
|
+
const fp_size = fingerBuffer.length;
|
|
1187
|
+
prep_struct.writeUInt16LE(fp_size, 0);
|
|
1188
|
+
const initPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_PREPARE_DATA, prep_struct);
|
|
1189
|
+
check_ACK_OK(initPacket);
|
|
1190
|
+
const fpPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_DATA, fingerBuffer);
|
|
1191
|
+
check_ACK_OK(fpPacket);
|
|
1192
|
+
const cheksumPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_CHECKSUM_BUFFER, '');
|
|
1193
|
+
check_ACK_OK(cheksumPacket);
|
|
1194
|
+
const checksum = cheksumPacket.readUInt32LE(8);
|
|
1195
|
+
const tmp_wreq = Buffer.alloc(6);
|
|
1196
|
+
tmp_wreq.writeUInt16LE(user.uid, 0);
|
|
1197
|
+
tmp_wreq.writeUIntLE(fid, 2, 1);
|
|
1198
|
+
tmp_wreq.writeUIntLE(fp_valid, 3, 1);
|
|
1199
|
+
tmp_wreq.writeUInt16LE(fp_size, 4);
|
|
1200
|
+
const tmp_wreqPacket = await this._zkTcp.executeCmd(COMMANDS.CMD_TMP_WRITE, tmp_wreq);
|
|
1201
|
+
check_ACK_OK(tmp_wreqPacket);
|
|
1202
|
+
const freeData = await this._zkTcp.executeCmd(COMMANDS.CMD_FREE_DATA, '');
|
|
1203
|
+
return check_ACK_OK(freeData);
|
|
1204
|
+
}
|
|
1205
|
+
catch (err) {
|
|
1206
|
+
throw err;
|
|
1207
|
+
}
|
|
1208
|
+
finally {
|
|
1209
|
+
await this._zkTcp.refreshData();
|
|
1210
|
+
await this._zkTcp.enableDevice();
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
class TransactionService {
|
|
1216
|
+
_zkTcp;
|
|
1217
|
+
constructor(zkTcp) {
|
|
1218
|
+
this._zkTcp = zkTcp;
|
|
1219
|
+
}
|
|
1220
|
+
async getAttendances(callbackInProcess = () => { }) {
|
|
1221
|
+
try {
|
|
1222
|
+
// Free any existing buffer data to prepare for a new request
|
|
1223
|
+
if (this._zkTcp.socket) {
|
|
1224
|
+
await this._zkTcp.freeData();
|
|
1225
|
+
}
|
|
1226
|
+
// Request attendance logs and handle chunked data
|
|
1227
|
+
const data = await this._zkTcp.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS, callbackInProcess);
|
|
1228
|
+
// Free buffer data after receiving the attendance logs
|
|
1229
|
+
if (this._zkTcp.socket) {
|
|
1230
|
+
await this._zkTcp.freeData();
|
|
1231
|
+
}
|
|
1232
|
+
// Constants for record processing
|
|
1233
|
+
const RECORD_PACKET_SIZE = 40;
|
|
1234
|
+
// Ensure data.data is a valid buffer
|
|
1235
|
+
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1236
|
+
throw new Error('Invalid data received');
|
|
1237
|
+
}
|
|
1238
|
+
// Process the record data
|
|
1239
|
+
let recordData = data.data.subarray(4); // Skip header
|
|
1240
|
+
const records = [];
|
|
1241
|
+
// Process each attendance record
|
|
1242
|
+
while (recordData.length >= RECORD_PACKET_SIZE) {
|
|
1243
|
+
const record = decodeRecordData40(recordData.subarray(0, RECORD_PACKET_SIZE));
|
|
1244
|
+
records.push({ ...record, ip: this._zkTcp.ip }); // Add IP address to each record
|
|
1245
|
+
recordData = recordData.subarray(RECORD_PACKET_SIZE); // Move to the next packet
|
|
1246
|
+
}
|
|
1247
|
+
// Return the list of attendance records
|
|
1248
|
+
return { data: records };
|
|
1249
|
+
}
|
|
1250
|
+
catch (err) {
|
|
1251
|
+
// Log and re-throw the error
|
|
1252
|
+
console.error('Error getting attendance records:', err);
|
|
1253
|
+
throw err; // Re-throw the error for handling by the caller
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
// Clears the attendance logs on the device
|
|
1257
|
+
async clearAttendanceLog() {
|
|
1258
|
+
try {
|
|
1259
|
+
// Execute the command to clear attendance logs
|
|
1260
|
+
await this._zkTcp.disableDevice();
|
|
1261
|
+
const buf = await this._zkTcp.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, '');
|
|
1262
|
+
await this._zkTcp.refreshData();
|
|
1263
|
+
await this._zkTcp.enableDevice();
|
|
1264
|
+
return !!buf;
|
|
1265
|
+
}
|
|
1266
|
+
catch (err) {
|
|
1267
|
+
// Log the error for debugging purposes
|
|
1268
|
+
console.error('Error clearing attendance log:', err);
|
|
1269
|
+
// Re-throw the error to be handled by the caller
|
|
1270
|
+
throw err;
|
|
1271
|
+
}
|
|
641
1272
|
}
|
|
642
1273
|
}
|
|
643
1274
|
|
|
@@ -673,6 +1304,8 @@ class ZTCP {
|
|
|
673
1304
|
verbose = false;
|
|
674
1305
|
packetNumber = 0;
|
|
675
1306
|
replyData = Buffer.from([]);
|
|
1307
|
+
_userService;
|
|
1308
|
+
_transactionService;
|
|
676
1309
|
constructor(ip, port, timeout, comm_key, verbose) {
|
|
677
1310
|
this.ip = ip;
|
|
678
1311
|
this.port = port;
|
|
@@ -680,6 +1313,8 @@ class ZTCP {
|
|
|
680
1313
|
this.replyId = 0;
|
|
681
1314
|
this.comm_key = comm_key;
|
|
682
1315
|
this.verbose = verbose;
|
|
1316
|
+
this._userService = new UserService(this);
|
|
1317
|
+
this._transactionService = new TransactionService(this);
|
|
683
1318
|
}
|
|
684
1319
|
createSocket(cbError, cbClose) {
|
|
685
1320
|
return new Promise((resolve, reject) => {
|
|
@@ -901,6 +1536,10 @@ class ZTCP {
|
|
|
901
1536
|
try {
|
|
902
1537
|
// Write the message to the socket and wait for a response
|
|
903
1538
|
const reply = await this.writeMessage(buf, command === COMMANDS.CMD_CONNECT || command === COMMANDS.CMD_EXIT);
|
|
1539
|
+
if (this.verbose) {
|
|
1540
|
+
let headers = decodeTCPHeader(reply);
|
|
1541
|
+
console.log('command: ', COMMANDS[headers.commandId], 'replyid: ', headers.replyId);
|
|
1542
|
+
}
|
|
904
1543
|
// Remove TCP header from the response
|
|
905
1544
|
const rReply = removeTcpHeader(reply);
|
|
906
1545
|
// Update sessionId for connection command responses
|
|
@@ -1050,89 +1689,14 @@ class ZTCP {
|
|
|
1050
1689
|
}
|
|
1051
1690
|
});
|
|
1052
1691
|
}
|
|
1053
|
-
/**
|
|
1054
|
-
* reject error when starting request data
|
|
1055
|
-
* @return {Record<string, User[] | Error>} when receiving requested data
|
|
1056
|
-
*/
|
|
1057
|
-
async getUsers() {
|
|
1058
|
-
try {
|
|
1059
|
-
// Free any existing buffer data to prepare for a new request
|
|
1060
|
-
if (this.socket) {
|
|
1061
|
-
await this.freeData();
|
|
1062
|
-
}
|
|
1063
|
-
// Request user data
|
|
1064
|
-
const data = await this.readWithBuffer(REQUEST_DATA.GET_USERS);
|
|
1065
|
-
// Free buffer data after receiving the data
|
|
1066
|
-
if (this.socket) {
|
|
1067
|
-
await this.freeData();
|
|
1068
|
-
}
|
|
1069
|
-
// Constants for user data processing
|
|
1070
|
-
const USER_PACKET_SIZE = 72;
|
|
1071
|
-
// Ensure data.data is a valid buffer
|
|
1072
|
-
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1073
|
-
throw new Error('Invalid data received');
|
|
1074
|
-
}
|
|
1075
|
-
let userData = data.data.subarray(4); // Skip the first 4 bytes (headers)
|
|
1076
|
-
const users = [];
|
|
1077
|
-
// Process each user packet
|
|
1078
|
-
while (userData.length >= USER_PACKET_SIZE) {
|
|
1079
|
-
// Decode user data and add to the users array
|
|
1080
|
-
const user = decodeUserData72(userData.subarray(0, USER_PACKET_SIZE));
|
|
1081
|
-
users.push(user);
|
|
1082
|
-
userData = userData.subarray(USER_PACKET_SIZE); // Move to the next packet
|
|
1083
|
-
}
|
|
1084
|
-
// Return the list of users
|
|
1085
|
-
return { data: users };
|
|
1086
|
-
}
|
|
1087
|
-
catch (err) {
|
|
1088
|
-
// Log the error for debugging
|
|
1089
|
-
console.error('Error getting users:', err);
|
|
1090
|
-
// Re-throw the error to be handled by the caller
|
|
1091
|
-
throw err;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
1692
|
/**
|
|
1095
1693
|
*
|
|
1096
|
-
* @param {*}
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
try {
|
|
1103
|
-
// Free any existing buffer data to prepare for a new request
|
|
1104
|
-
if (this.socket) {
|
|
1105
|
-
await this.freeData();
|
|
1106
|
-
}
|
|
1107
|
-
// Request attendance logs and handle chunked data
|
|
1108
|
-
const data = await this.readWithBuffer(REQUEST_DATA.GET_ATTENDANCE_LOGS, callbackInProcess);
|
|
1109
|
-
// Free buffer data after receiving the attendance logs
|
|
1110
|
-
if (this.socket) {
|
|
1111
|
-
await this.freeData();
|
|
1112
|
-
}
|
|
1113
|
-
// Constants for record processing
|
|
1114
|
-
const RECORD_PACKET_SIZE = 40;
|
|
1115
|
-
// Ensure data.data is a valid buffer
|
|
1116
|
-
if (!data.data || !(data.data instanceof Buffer)) {
|
|
1117
|
-
throw new Error('Invalid data received');
|
|
1118
|
-
}
|
|
1119
|
-
// Process the record data
|
|
1120
|
-
let recordData = data.data.subarray(4); // Skip header
|
|
1121
|
-
const records = [];
|
|
1122
|
-
// Process each attendance record
|
|
1123
|
-
while (recordData.length >= RECORD_PACKET_SIZE) {
|
|
1124
|
-
const record = decodeRecordData40(recordData.subarray(0, RECORD_PACKET_SIZE));
|
|
1125
|
-
records.push({ ...record, ip: this.ip }); // Add IP address to each record
|
|
1126
|
-
recordData = recordData.subarray(RECORD_PACKET_SIZE); // Move to the next packet
|
|
1127
|
-
}
|
|
1128
|
-
// Return the list of attendance records
|
|
1129
|
-
return { data: records };
|
|
1130
|
-
}
|
|
1131
|
-
catch (err) {
|
|
1132
|
-
// Log and re-throw the error
|
|
1133
|
-
console.error('Error getting attendance records:', err);
|
|
1134
|
-
throw err; // Re-throw the error for handling by the caller
|
|
1135
|
-
}
|
|
1694
|
+
* @param {*} callbackInProcess
|
|
1695
|
+
* reject error when starting request data
|
|
1696
|
+
* return { data: records, err: Error } when receiving requested data
|
|
1697
|
+
*/
|
|
1698
|
+
async getAttendances(callbackInProcess = () => { }) {
|
|
1699
|
+
return await this._transactionService.getAttendances(callbackInProcess);
|
|
1136
1700
|
}
|
|
1137
1701
|
async freeData() {
|
|
1138
1702
|
try {
|
|
@@ -1328,17 +1892,26 @@ class ZTCP {
|
|
|
1328
1892
|
}
|
|
1329
1893
|
async getSerialNumber() {
|
|
1330
1894
|
const keyword = '~SerialNumber';
|
|
1895
|
+
let serialNumber = '';
|
|
1896
|
+
let count = 10;
|
|
1331
1897
|
try {
|
|
1332
1898
|
// Execute the command to get serial number
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
.
|
|
1340
|
-
|
|
1341
|
-
|
|
1899
|
+
/**
|
|
1900
|
+
* @dev implemented a counter and a while loop because sometimes serial number parses wrong for some reason
|
|
1901
|
+
* */
|
|
1902
|
+
while (serialNumber.length !== 13 && count > 0) {
|
|
1903
|
+
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1904
|
+
// Extract and format the serial number from the response data
|
|
1905
|
+
const SN = data.slice(8) // Skip the first 8 bytes (header)
|
|
1906
|
+
.toString('utf-8') // Convert buffer to string
|
|
1907
|
+
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1908
|
+
.replace('=', '') // Remove sometines last number is a character equal to = or unknow character
|
|
1909
|
+
.replace(/\u0000/g, ''); // Remove null characters
|
|
1910
|
+
if (serialNumber.length !== 13 && this.verbose) {
|
|
1911
|
+
console.warn('Serial number length not equal to 13, check');
|
|
1912
|
+
}
|
|
1913
|
+
count--;
|
|
1914
|
+
serialNumber = SN;
|
|
1342
1915
|
}
|
|
1343
1916
|
return serialNumber;
|
|
1344
1917
|
}
|
|
@@ -1450,11 +2023,10 @@ class ZTCP {
|
|
|
1450
2023
|
// Execute the command to get the PIN information
|
|
1451
2024
|
const data = await this.executeCmd(COMMANDS.CMD_OPTIONS_RRQ, keyword);
|
|
1452
2025
|
// Extract and format the PIN information from the response data
|
|
1453
|
-
// Remove null characters
|
|
1454
2026
|
return data.slice(8) // Skip the first 8 bytes (header)
|
|
1455
2027
|
.toString('ascii') // Convert buffer to ASCII string
|
|
1456
2028
|
.replace(`${keyword}=`, '') // Remove the keyword prefix
|
|
1457
|
-
.replace(/\u0000/g, '');
|
|
2029
|
+
.replace(/\u0000/g, ''); // Remove null characters 0x00
|
|
1458
2030
|
}
|
|
1459
2031
|
catch (err) {
|
|
1460
2032
|
// Log the error for debugging
|
|
@@ -1506,7 +2078,9 @@ class ZTCP {
|
|
|
1506
2078
|
// Execute the command to get firmware information
|
|
1507
2079
|
const data = await this.executeCmd(1100, '');
|
|
1508
2080
|
// Extract and return the firmware version from the response data
|
|
1509
|
-
return data.slice(8)
|
|
2081
|
+
return data.slice(8) // Skip the first 8 bytes (header)
|
|
2082
|
+
.toString('ascii') // convert to ASCII string
|
|
2083
|
+
.replace(/\u0000/g, ''); // remove x00
|
|
1510
2084
|
}
|
|
1511
2085
|
catch (err) {
|
|
1512
2086
|
// Log the error for debugging
|
|
@@ -1572,59 +2146,6 @@ class ZTCP {
|
|
|
1572
2146
|
throw err;
|
|
1573
2147
|
}
|
|
1574
2148
|
}
|
|
1575
|
-
async setUser(uid, userid, name, password, role = 0, cardno = 0) {
|
|
1576
|
-
try {
|
|
1577
|
-
// Validate input parameters
|
|
1578
|
-
if (uid <= 0 || uid > 3000 ||
|
|
1579
|
-
userid.length > 9 ||
|
|
1580
|
-
name.length > 24 ||
|
|
1581
|
-
password.length > 8 ||
|
|
1582
|
-
typeof role !== 'number' ||
|
|
1583
|
-
cardno.toString().length > 10) {
|
|
1584
|
-
throw new Error('Invalid input parameters');
|
|
1585
|
-
}
|
|
1586
|
-
// Allocate and initialize the buffer
|
|
1587
|
-
const commandBuffer = Buffer.alloc(72);
|
|
1588
|
-
// Fill the buffer with user data
|
|
1589
|
-
commandBuffer.writeUInt16LE(uid, 0);
|
|
1590
|
-
commandBuffer.writeUInt16LE(role, 2);
|
|
1591
|
-
commandBuffer.write(password.padEnd(8, '\0'), 3, 8); // Ensure password is 8 bytes
|
|
1592
|
-
commandBuffer.write(name.padEnd(24, '\0'), 11, 24); // Ensure name is 24 bytes
|
|
1593
|
-
commandBuffer.writeUInt16LE(cardno, 35);
|
|
1594
|
-
commandBuffer.writeUInt32LE(0, 40); // Placeholder or reserved field
|
|
1595
|
-
commandBuffer.write(userid.padEnd(9, '\0'), 48, 9); // Ensure userid is 9 bytes
|
|
1596
|
-
// Send the command and return the result
|
|
1597
|
-
const created = await this.executeCmd(COMMANDS.CMD_USER_WRQ, commandBuffer);
|
|
1598
|
-
return !!created;
|
|
1599
|
-
}
|
|
1600
|
-
catch (err) {
|
|
1601
|
-
// Log error details for debugging
|
|
1602
|
-
console.error('Error setting user:', err);
|
|
1603
|
-
// Re-throw error for upstream handling
|
|
1604
|
-
throw err;
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
async deleteUser(uid) {
|
|
1608
|
-
try {
|
|
1609
|
-
// Validate input parameter
|
|
1610
|
-
if (uid <= 0 || uid > 3000) {
|
|
1611
|
-
throw new Error('Invalid UID: must be between 1 and 3000');
|
|
1612
|
-
}
|
|
1613
|
-
// Allocate and initialize the buffer
|
|
1614
|
-
const commandBuffer = Buffer.alloc(72);
|
|
1615
|
-
// Write UID to the buffer
|
|
1616
|
-
commandBuffer.writeUInt16LE(uid, 0);
|
|
1617
|
-
// Send the delete command and return the result
|
|
1618
|
-
const deleted = await this.executeCmd(COMMANDS.CMD_DELETE_USER, commandBuffer);
|
|
1619
|
-
return !!deleted;
|
|
1620
|
-
}
|
|
1621
|
-
catch (err) {
|
|
1622
|
-
// Log error details for debugging
|
|
1623
|
-
console.error('Error deleting user:', err);
|
|
1624
|
-
// Re-throw error for upstream handling
|
|
1625
|
-
throw err;
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
2149
|
async getAttendanceSize() {
|
|
1629
2150
|
try {
|
|
1630
2151
|
// Execute command to get free sizes
|
|
@@ -1641,22 +2162,27 @@ class ZTCP {
|
|
|
1641
2162
|
}
|
|
1642
2163
|
// Clears the attendance logs on the device
|
|
1643
2164
|
async clearAttendanceLog() {
|
|
1644
|
-
|
|
1645
|
-
// Execute the command to clear attendance logs
|
|
1646
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, '');
|
|
1647
|
-
}
|
|
1648
|
-
catch (err) {
|
|
1649
|
-
// Log the error for debugging purposes
|
|
1650
|
-
console.error('Error clearing attendance log:', err);
|
|
1651
|
-
// Re-throw the error to be handled by the caller
|
|
1652
|
-
throw err;
|
|
1653
|
-
}
|
|
2165
|
+
return await this._transactionService.clearAttendanceLog();
|
|
1654
2166
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
2167
|
+
/**
|
|
2168
|
+
* Clears all data on the device
|
|
2169
|
+
* @value 1 Attendance records
|
|
2170
|
+
* @value 2 Fingerprint templates
|
|
2171
|
+
* @value 3 None
|
|
2172
|
+
* @value 4 Operation records
|
|
2173
|
+
* @value 5 User information
|
|
2174
|
+
* @default 0 Delete all
|
|
2175
|
+
*/
|
|
2176
|
+
async clearData(value) {
|
|
1657
2177
|
try {
|
|
1658
2178
|
// Execute the command to clear all data
|
|
1659
|
-
|
|
2179
|
+
await this.disableDevice();
|
|
2180
|
+
if (!value)
|
|
2181
|
+
value = 3;
|
|
2182
|
+
const buf = await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, value.toString());
|
|
2183
|
+
await this.refreshData();
|
|
2184
|
+
await this.enableDevice();
|
|
2185
|
+
return !!buf;
|
|
1660
2186
|
}
|
|
1661
2187
|
catch (err) {
|
|
1662
2188
|
// Log the error for debugging purposes
|
|
@@ -1703,33 +2229,7 @@ class ZTCP {
|
|
|
1703
2229
|
* @returns {Record<string, Finger[]>}
|
|
1704
2230
|
*/
|
|
1705
2231
|
async getTemplates(callbackInProcess = () => { }) {
|
|
1706
|
-
|
|
1707
|
-
try {
|
|
1708
|
-
await this.getSizes();
|
|
1709
|
-
if (this.fp_count == 0)
|
|
1710
|
-
return { data: [] };
|
|
1711
|
-
await this.freeData();
|
|
1712
|
-
await this.disableDevice();
|
|
1713
|
-
const Buffer = await this.readWithBuffer(REQUEST_DATA.GET_TEMPLATES);
|
|
1714
|
-
let templateData = Buffer.data.subarray(4);
|
|
1715
|
-
let totalSize = Buffer.data.readUIntLE(0, 4);
|
|
1716
|
-
while (totalSize) {
|
|
1717
|
-
const buf = templateData.subarray(0, 6);
|
|
1718
|
-
const size = buf.readUIntLE(0, 2);
|
|
1719
|
-
templates.push(new Finger(buf.readUIntLE(2, 2), buf.readUIntLE(4, 1), buf.readUIntLE(5, 1), templateData.subarray(6, size)));
|
|
1720
|
-
templateData = templateData.subarray(size);
|
|
1721
|
-
totalSize -= size;
|
|
1722
|
-
}
|
|
1723
|
-
return { data: templates };
|
|
1724
|
-
}
|
|
1725
|
-
catch (err) {
|
|
1726
|
-
this.verbose && console.log("Error getting templates", err);
|
|
1727
|
-
return { data: templates };
|
|
1728
|
-
}
|
|
1729
|
-
finally {
|
|
1730
|
-
await this.enableDevice();
|
|
1731
|
-
await this.freeData();
|
|
1732
|
-
}
|
|
2232
|
+
return await this._userService.getTemplates(callbackInProcess);
|
|
1733
2233
|
}
|
|
1734
2234
|
/**
|
|
1735
2235
|
* Return size
|
|
@@ -1805,197 +2305,6 @@ class ZTCP {
|
|
|
1805
2305
|
throw new ZkError(e, COMMANDS.CMD_DATA, this.ip);
|
|
1806
2306
|
}
|
|
1807
2307
|
}
|
|
1808
|
-
/**
|
|
1809
|
-
* save user and template
|
|
1810
|
-
*
|
|
1811
|
-
* @param {User | number | string} user - User class object | uid | user_id
|
|
1812
|
-
* @param {Finger[]} fingers - Array of finger class. `0 <= index <= 9`
|
|
1813
|
-
*/
|
|
1814
|
-
async saveUserTemplate(user, fingers = []) {
|
|
1815
|
-
if (fingers.length > 9 || fingers.length == 0)
|
|
1816
|
-
throw new Error("maximum finger length is 10 and can't be empty");
|
|
1817
|
-
try {
|
|
1818
|
-
await this.disableDevice();
|
|
1819
|
-
const users = await this.getUsers();
|
|
1820
|
-
//check users exists
|
|
1821
|
-
if (!users.data.some(u => u.uid == user.uid || +u.user_id == +user.user_id))
|
|
1822
|
-
throw new Error("error validating user input");
|
|
1823
|
-
if (!(user instanceof User)) {
|
|
1824
|
-
let tusers = users.data.filter(x => x.uid === +user.uid);
|
|
1825
|
-
if (tusers.length === 1) {
|
|
1826
|
-
user = tusers[0];
|
|
1827
|
-
}
|
|
1828
|
-
else {
|
|
1829
|
-
tusers = users.data.filter(x => x.user_id === String(user));
|
|
1830
|
-
if (tusers.length === 1) {
|
|
1831
|
-
user = tusers[0];
|
|
1832
|
-
}
|
|
1833
|
-
else {
|
|
1834
|
-
throw new Error("Can't find user");
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
if (fingers instanceof Finger) {
|
|
1839
|
-
fingers = [fingers];
|
|
1840
|
-
}
|
|
1841
|
-
let fpack = Buffer.alloc(0);
|
|
1842
|
-
let table = Buffer.alloc(0);
|
|
1843
|
-
const fnum = 0x10;
|
|
1844
|
-
let tstart = 0;
|
|
1845
|
-
for (const finger of fingers) {
|
|
1846
|
-
const tfp = finger.repackOnly();
|
|
1847
|
-
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
|
|
1848
|
-
tableEntry.writeInt8(2, 0);
|
|
1849
|
-
tableEntry.writeUInt16LE(user.uid, 1);
|
|
1850
|
-
tableEntry.writeInt8(fnum + finger.fid, 3);
|
|
1851
|
-
tableEntry.writeUInt32LE(tstart, 4);
|
|
1852
|
-
table = Buffer.concat([table, tableEntry]);
|
|
1853
|
-
tstart += tfp.length;
|
|
1854
|
-
fpack = Buffer.concat([fpack, tfp]);
|
|
1855
|
-
}
|
|
1856
|
-
let upack;
|
|
1857
|
-
if (this.userPacketSize === 28) {
|
|
1858
|
-
upack = user.repack29();
|
|
1859
|
-
}
|
|
1860
|
-
else {
|
|
1861
|
-
upack = user.repack73();
|
|
1862
|
-
}
|
|
1863
|
-
const head = Buffer.alloc(12); // III = 3*4 bytes
|
|
1864
|
-
head.writeUInt32LE(upack.length, 0);
|
|
1865
|
-
head.writeUInt32LE(table.length, 4);
|
|
1866
|
-
head.writeUInt32LE(fpack.length, 8);
|
|
1867
|
-
const packet = Buffer.concat([head, upack, table, fpack]);
|
|
1868
|
-
const bufferResponse = await this.sendWithBuffer(packet);
|
|
1869
|
-
const command = 110;
|
|
1870
|
-
const commandString = Buffer.alloc(8); // <IHH = I(4) + H(2) + H(2) = 8 bytes
|
|
1871
|
-
commandString.writeUInt32LE(12, 0);
|
|
1872
|
-
commandString.writeUInt16LE(0, 4);
|
|
1873
|
-
commandString.writeUInt16LE(8, 6);
|
|
1874
|
-
const cmdResponse = await this.executeCmd(command, commandString);
|
|
1875
|
-
if (this.verbose)
|
|
1876
|
-
console.log("finally bulk save user templates: \n", cmdResponse.readUInt16LE(0));
|
|
1877
|
-
}
|
|
1878
|
-
catch (error) {
|
|
1879
|
-
throw error;
|
|
1880
|
-
}
|
|
1881
|
-
finally {
|
|
1882
|
-
await this.refreshData();
|
|
1883
|
-
await this.enableDevice();
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
async deleteFinger(uid, fid) {
|
|
1887
|
-
try {
|
|
1888
|
-
const buf = Buffer.alloc(4);
|
|
1889
|
-
buf.writeUInt16LE(uid, 0);
|
|
1890
|
-
buf.writeUint16LE(fid, 2);
|
|
1891
|
-
const reply = await this.executeCmd(COMMANDS.CMD_DELETE_USERTEMP, buf);
|
|
1892
|
-
return !!reply;
|
|
1893
|
-
}
|
|
1894
|
-
catch (error) {
|
|
1895
|
-
throw new Error("Can't save utemp");
|
|
1896
|
-
}
|
|
1897
|
-
finally {
|
|
1898
|
-
await this.refreshData();
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
async enrollUser(uid, tempId, userId = '') {
|
|
1902
|
-
let done = false;
|
|
1903
|
-
try {
|
|
1904
|
-
//validate user exists
|
|
1905
|
-
const users = await this.getUsers();
|
|
1906
|
-
const filteredUsers = users.data.filter(x => x.uid === uid);
|
|
1907
|
-
if (filteredUsers.length >= 1) {
|
|
1908
|
-
userId = filteredUsers[0].user_id;
|
|
1909
|
-
}
|
|
1910
|
-
else {
|
|
1911
|
-
throw new Error("user not found");
|
|
1912
|
-
}
|
|
1913
|
-
const userBuf = Buffer.alloc(24);
|
|
1914
|
-
userBuf.write(userId.toString(), 0, 24, 'ascii');
|
|
1915
|
-
let commandString = Buffer.concat([
|
|
1916
|
-
userBuf,
|
|
1917
|
-
Buffer.from([tempId, 1])
|
|
1918
|
-
]);
|
|
1919
|
-
const cancel = await this.cancelCapture();
|
|
1920
|
-
const cmdResponse = await this.executeCmd(COMMANDS.CMD_STARTENROLL, commandString);
|
|
1921
|
-
this.timeout = 60000; // 60 seconds timeout
|
|
1922
|
-
let attempts = 3;
|
|
1923
|
-
while (attempts > 0) {
|
|
1924
|
-
if (this.verbose)
|
|
1925
|
-
console.log(`A:${attempts} esperando primer regevent`);
|
|
1926
|
-
let dataRecv = await this.readSocket(17);
|
|
1927
|
-
await this.ackOk();
|
|
1928
|
-
if (dataRecv.length > 16) {
|
|
1929
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1930
|
-
const res = padded.readUInt16LE(16);
|
|
1931
|
-
if (this.verbose)
|
|
1932
|
-
console.log(`res ${res}`);
|
|
1933
|
-
if (res === 0 || res === 6 || res === 4) {
|
|
1934
|
-
if (this.verbose)
|
|
1935
|
-
console.log("posible timeout o reg Fallido");
|
|
1936
|
-
break;
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
if (this.verbose)
|
|
1940
|
-
console.log(`A:${attempts} esperando 2do regevent`);
|
|
1941
|
-
dataRecv = await this.readSocket(17);
|
|
1942
|
-
await this.ackOk();
|
|
1943
|
-
if (this.verbose)
|
|
1944
|
-
console.log(dataRecv);
|
|
1945
|
-
if (dataRecv.length > 8) {
|
|
1946
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1947
|
-
const res = padded.readUInt16LE(16);
|
|
1948
|
-
if (this.verbose)
|
|
1949
|
-
console.log(`res ${res}`);
|
|
1950
|
-
if (res === 6 || res === 4) {
|
|
1951
|
-
if (this.verbose)
|
|
1952
|
-
console.log("posible timeout o reg Fallido");
|
|
1953
|
-
break;
|
|
1954
|
-
}
|
|
1955
|
-
else if (res === 0x64) {
|
|
1956
|
-
if (this.verbose)
|
|
1957
|
-
console.log("ok, continue?");
|
|
1958
|
-
attempts--;
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
if (attempts === 0) {
|
|
1963
|
-
const dataRecv = await this.readSocket(17);
|
|
1964
|
-
await this.ackOk();
|
|
1965
|
-
if (this.verbose)
|
|
1966
|
-
console.log(dataRecv.toString('hex'));
|
|
1967
|
-
const padded = Buffer.concat([dataRecv, Buffer.alloc(24 - dataRecv.length)]);
|
|
1968
|
-
let res = padded.readUInt16LE(16);
|
|
1969
|
-
if (this.verbose)
|
|
1970
|
-
console.log(`res ${res}`);
|
|
1971
|
-
if (res === 5) {
|
|
1972
|
-
if (this.verbose)
|
|
1973
|
-
console.log("finger duplicate");
|
|
1974
|
-
}
|
|
1975
|
-
if (res === 6 || res === 4) {
|
|
1976
|
-
if (this.verbose)
|
|
1977
|
-
console.log("posible timeout");
|
|
1978
|
-
}
|
|
1979
|
-
if (res === 0) {
|
|
1980
|
-
const size = padded.readUInt16LE(10);
|
|
1981
|
-
const pos = padded.readUInt16LE(12);
|
|
1982
|
-
if (this.verbose)
|
|
1983
|
-
console.log(`enroll ok ${size} ${pos}`);
|
|
1984
|
-
done = true;
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
//this.__sock.setTimeout(this.__timeout);
|
|
1988
|
-
await this.regEvent(0); // TODO: test
|
|
1989
|
-
return done;
|
|
1990
|
-
}
|
|
1991
|
-
catch (error) {
|
|
1992
|
-
throw error;
|
|
1993
|
-
}
|
|
1994
|
-
finally {
|
|
1995
|
-
await this.cancelCapture();
|
|
1996
|
-
await this.verifyUser(undefined);
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
2308
|
async readSocket(length, cb = null) {
|
|
2000
2309
|
let replyBufer = Buffer.from([]);
|
|
2001
2310
|
let totalPackets = 0;
|
|
@@ -2045,15 +2354,6 @@ class ZTCP {
|
|
|
2045
2354
|
throw new ZkError(e, COMMANDS.CMD_REG_EVENT, this.ip);
|
|
2046
2355
|
}
|
|
2047
2356
|
}
|
|
2048
|
-
async ackOk() {
|
|
2049
|
-
try {
|
|
2050
|
-
const buf = createTCPHeader(COMMANDS.CMD_ACK_OK, this.sessionId, Constants.USHRT_MAX - 1, Buffer.from([]));
|
|
2051
|
-
this.socket.write(buf);
|
|
2052
|
-
}
|
|
2053
|
-
catch (e) {
|
|
2054
|
-
throw new ZkError(e, COMMANDS.CMD_ACK_OK, this.ip);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
2357
|
async cancelCapture() {
|
|
2058
2358
|
try {
|
|
2059
2359
|
const reply = await this.executeCmd(COMMANDS.CMD_CANCELCAPTURE, '');
|
|
@@ -2063,22 +2363,6 @@ class ZTCP {
|
|
|
2063
2363
|
throw new ZkError(e, COMMANDS.CMD_CANCELCAPTURE, this.ip);
|
|
2064
2364
|
}
|
|
2065
2365
|
}
|
|
2066
|
-
async verifyUser(uid) {
|
|
2067
|
-
try {
|
|
2068
|
-
let command_string = '';
|
|
2069
|
-
if (uid) {
|
|
2070
|
-
command_string = Buffer.alloc(4);
|
|
2071
|
-
command_string.writeUInt32LE(uid, 0);
|
|
2072
|
-
}
|
|
2073
|
-
const reply = await this.executeCmd(COMMANDS.CMD_STARTVERIFY, command_string);
|
|
2074
|
-
if (this.verbose)
|
|
2075
|
-
console.log(reply.readUInt16LE(0));
|
|
2076
|
-
return !!reply;
|
|
2077
|
-
}
|
|
2078
|
-
catch (error) {
|
|
2079
|
-
console.error(error);
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
2366
|
async restartDevice() {
|
|
2083
2367
|
try {
|
|
2084
2368
|
await this.executeCmd(COMMANDS.CMD_RESTART, '');
|
|
@@ -2463,7 +2747,7 @@ class ZUDP {
|
|
|
2463
2747
|
}
|
|
2464
2748
|
async clearAttendanceLog() {
|
|
2465
2749
|
try {
|
|
2466
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, Buffer.alloc(0));
|
|
2750
|
+
return !!await this.executeCmd(COMMANDS.CMD_CLEAR_ATTLOG, Buffer.alloc(0));
|
|
2467
2751
|
}
|
|
2468
2752
|
catch (err) {
|
|
2469
2753
|
console.error('Error clearing attendance log:', err);
|
|
@@ -2472,7 +2756,7 @@ class ZUDP {
|
|
|
2472
2756
|
}
|
|
2473
2757
|
async clearData() {
|
|
2474
2758
|
try {
|
|
2475
|
-
return await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, Buffer.alloc(0));
|
|
2759
|
+
return !!await this.executeCmd(COMMANDS.CMD_CLEAR_DATA, Buffer.alloc(0));
|
|
2476
2760
|
}
|
|
2477
2761
|
catch (err) {
|
|
2478
2762
|
console.error('Error clearing data:', err);
|
|
@@ -2663,7 +2947,7 @@ class Zklib {
|
|
|
2663
2947
|
}
|
|
2664
2948
|
}
|
|
2665
2949
|
async getUsers() {
|
|
2666
|
-
return this.functionWrapper(() => this.ztcp.getUsers(), () => this.zudp.getUsers(), 'GET_USERS');
|
|
2950
|
+
return this.functionWrapper(() => this.ztcp._userService.getUsers(), () => this.zudp.getUsers(), 'GET_USERS');
|
|
2667
2951
|
}
|
|
2668
2952
|
async getTime() {
|
|
2669
2953
|
return this.functionWrapper(() => this.ztcp.getTime(), () => this.zudp.getTime(), 'GET_TIME');
|
|
@@ -2713,11 +2997,22 @@ class Zklib {
|
|
|
2713
2997
|
async getFirmware() {
|
|
2714
2998
|
return this.functionWrapper(() => this.ztcp.getFirmware(), async () => { throw new Error('UDP get firmware not supported'); }, 'GET_FIRMWARE');
|
|
2715
2999
|
}
|
|
2716
|
-
|
|
2717
|
-
|
|
3000
|
+
/** Update or create a user if user id/pin not exists
|
|
3001
|
+
* @param user_id {string} user id/pin for customer
|
|
3002
|
+
* @param name {string} user name
|
|
3003
|
+
* @param password {string} user password
|
|
3004
|
+
* @param role {number} role/privilege id number
|
|
3005
|
+
* @param cardno {number} card number/id
|
|
3006
|
+
*/
|
|
3007
|
+
async setUser(user_id, name, password, role = 0, cardno = 0) {
|
|
3008
|
+
return this.functionWrapper(() => this.ztcp._userService.setUser(user_id, name, password, role, cardno), async () => { throw new Error('UDP set user not supported'); }, 'SET_USER');
|
|
2718
3009
|
}
|
|
2719
|
-
|
|
2720
|
-
|
|
3010
|
+
/**
|
|
3011
|
+
* Delete user by a given user id/pin
|
|
3012
|
+
* @param user_id {string}
|
|
3013
|
+
*/
|
|
3014
|
+
async deleteUser(user_id) {
|
|
3015
|
+
return this.functionWrapper(() => this.ztcp._userService.DeleteUser(user_id), async () => { throw new Error('UDP delete user not supported'); }, 'DELETE_USER');
|
|
2721
3016
|
}
|
|
2722
3017
|
async getAttendanceSize() {
|
|
2723
3018
|
return this.functionWrapper(() => this.ztcp.getAttendanceSize(), async () => { throw new Error('UDP get attendance size not supported'); }, 'GET_ATTENDANCE_SIZE');
|
|
@@ -2731,25 +3026,55 @@ class Zklib {
|
|
|
2731
3026
|
async getTemplates() {
|
|
2732
3027
|
return this.functionWrapper(() => this.ztcp.getTemplates(), async () => { throw new Error('UDP get templates not supported'); }, 'GET_TEMPLATES');
|
|
2733
3028
|
}
|
|
2734
|
-
|
|
2735
|
-
|
|
3029
|
+
/**
|
|
3030
|
+
* Get a user template for a given user id/pin and finger id
|
|
3031
|
+
* @param user_id {string} user id/pin
|
|
3032
|
+
* @param fid {number} finger index
|
|
3033
|
+
*/
|
|
3034
|
+
async getUserTemplate(user_id, fid) {
|
|
3035
|
+
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');
|
|
3036
|
+
}
|
|
3037
|
+
/**
|
|
3038
|
+
* Upload a single fingerprint for a given user id
|
|
3039
|
+
* @param user_id {string} user id/pin for customer
|
|
3040
|
+
* @param fingerTemplate {string} finger template in base64 string
|
|
3041
|
+
* @param fid {number} finger id is a number between 0 and 9
|
|
3042
|
+
* @param fp_valid {number} finger flag. e.g., valid=1, duress=3
|
|
3043
|
+
*/
|
|
3044
|
+
async uploadFingerTemplate(user_id, fingerTemplate, fid, fp_valid) {
|
|
3045
|
+
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');
|
|
3046
|
+
}
|
|
3047
|
+
/**
|
|
3048
|
+
* save user and template
|
|
3049
|
+
*
|
|
3050
|
+
* @param {string} user_id - user id for customer
|
|
3051
|
+
* @param {Finger[]} fingers - Array of finger class
|
|
3052
|
+
*/
|
|
3053
|
+
async saveUserTemplate(user_id, fingers = []) {
|
|
3054
|
+
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');
|
|
2736
3055
|
}
|
|
2737
|
-
|
|
3056
|
+
/**
|
|
3057
|
+
* Delete a single finger template by user id and finger index
|
|
3058
|
+
* @param user_id {string} user id/pin for customer
|
|
3059
|
+
* @param fid {number} finger index
|
|
3060
|
+
*/
|
|
3061
|
+
async deleteFinger(user_id, fid) {
|
|
2738
3062
|
if (fid > 9 || 0 > fid)
|
|
2739
3063
|
throw new Error("fid params out of index");
|
|
2740
|
-
|
|
2741
|
-
throw new Error("fid params out of index");
|
|
2742
|
-
return this.functionWrapper(() => this.ztcp.deleteFinger(uid, fid), async () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
|
|
3064
|
+
return this.functionWrapper(() => this.ztcp._userService.deleteFinger(user_id, fid), async () => { throw new Error('UDP delete finger not supported'); }, 'DELETE_FINGER');
|
|
2743
3065
|
}
|
|
2744
|
-
|
|
3066
|
+
/**
|
|
3067
|
+
* Start to enroll a finger template
|
|
3068
|
+
* @param user_id {string} user id/pin for customer
|
|
3069
|
+
* @param temp_id {number} finger index
|
|
3070
|
+
*/
|
|
3071
|
+
async enrollUser(user_id, temp_id) {
|
|
2745
3072
|
if (temp_id < 0 || temp_id > 9)
|
|
2746
3073
|
throw new Error("temp_id out of range 0-9");
|
|
2747
|
-
|
|
2748
|
-
throw new Error("uid out of range 1-3000");
|
|
2749
|
-
return this.functionWrapper(() => this.ztcp.enrollUser(uid, temp_id, user_id), async () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
|
|
3074
|
+
return this.functionWrapper(() => this.ztcp._userService.enrollInfo(user_id, temp_id), async () => { throw new Error('UDP enroll user not supported'); }, 'ENROLL_USER');
|
|
2750
3075
|
}
|
|
2751
|
-
async verifyUser(
|
|
2752
|
-
return this.functionWrapper(() => this.ztcp.
|
|
3076
|
+
async verifyUser(user_id) {
|
|
3077
|
+
return this.functionWrapper(() => this.ztcp._userService.verify(user_id), async () => { throw new Error('UDP verify user not supported'); }, 'VERIFY_USER');
|
|
2753
3078
|
}
|
|
2754
3079
|
async restartDevice() {
|
|
2755
3080
|
return this.functionWrapper(() => this.ztcp.restartDevice(), async () => { throw new Error('UDP restart device not supported'); }, 'RESTART_DEVICE');
|