@zwave-js/cc 15.31.2 → 15.32.0
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/build/cjs/cc/AlarmSensorCC.js +2 -3
- package/build/cjs/cc/AlarmSensorCC.js.map +2 -2
- package/build/cjs/cc/AssociationGroupInfoCC.js +5 -2
- package/build/cjs/cc/AssociationGroupInfoCC.js.map +2 -2
- package/build/cjs/cc/ColorSwitchCC.js +2 -3
- package/build/cjs/cc/ColorSwitchCC.js.map +2 -2
- package/build/cjs/cc/ConfigurationCC.d.ts +2 -0
- package/build/cjs/cc/ConfigurationCC.js +28 -8
- package/build/cjs/cc/ConfigurationCC.js.map +2 -2
- package/build/cjs/cc/EntryControlCC.js +3 -2
- package/build/cjs/cc/EntryControlCC.js.map +2 -2
- package/build/cjs/cc/IndicatorCC.js +3 -3
- package/build/cjs/cc/IndicatorCC.js.map +2 -2
- package/build/cjs/cc/IrrigationCC.js.map +1 -1
- package/build/cjs/cc/LanguageCC.js +6 -2
- package/build/cjs/cc/LanguageCC.js.map +2 -2
- package/build/cjs/cc/ManufacturerSpecificCC.js +1 -1
- package/build/cjs/cc/ManufacturerSpecificCC.js.map +2 -2
- package/build/cjs/cc/MeterCC.js +25 -4
- package/build/cjs/cc/MeterCC.js.map +2 -2
- package/build/cjs/cc/NodeNamingCC.js +2 -2
- package/build/cjs/cc/NodeNamingCC.js.map +2 -2
- package/build/cjs/cc/NotificationCC.js +10 -11
- package/build/cjs/cc/NotificationCC.js.map +2 -2
- package/build/cjs/cc/Security2CC.js +11 -6
- package/build/cjs/cc/Security2CC.js.map +2 -2
- package/build/cjs/cc/SecurityCC.js +2 -1
- package/build/cjs/cc/SecurityCC.js.map +2 -2
- package/build/cjs/cc/SoundSwitchCC.js +1 -1
- package/build/cjs/cc/SoundSwitchCC.js.map +2 -2
- package/build/cjs/cc/ThermostatSetpointCC.js +2 -1
- package/build/cjs/cc/ThermostatSetpointCC.js.map +2 -2
- package/build/cjs/cc/UserCredentialCC.d.ts +6 -0
- package/build/cjs/cc/UserCredentialCC.js +81 -6
- package/build/cjs/cc/UserCredentialCC.js.map +2 -2
- package/build/cjs/lib/Security2/Extension.js +2 -1
- package/build/cjs/lib/Security2/Extension.js.map +2 -2
- package/build/cjs/lib/securityLogging.d.ts +6 -0
- package/build/cjs/lib/securityLogging.js +34 -0
- package/build/cjs/lib/securityLogging.js.map +7 -0
- package/build/cjs/lib/serializers.js +3 -0
- package/build/cjs/lib/serializers.js.map +2 -2
- package/build/esm/cc/AlarmSensorCC.d.ts.map +1 -1
- package/build/esm/cc/AlarmSensorCC.js +5 -3
- package/build/esm/cc/AlarmSensorCC.js.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.d.ts.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.js +10 -6
- package/build/esm/cc/AssociationGroupInfoCC.js.map +1 -1
- package/build/esm/cc/ColorSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/ColorSwitchCC.js +2 -4
- package/build/esm/cc/ColorSwitchCC.js.map +1 -1
- package/build/esm/cc/ConfigurationCC.d.ts +2 -0
- package/build/esm/cc/ConfigurationCC.d.ts.map +1 -1
- package/build/esm/cc/ConfigurationCC.js +34 -13
- package/build/esm/cc/ConfigurationCC.js.map +1 -1
- package/build/esm/cc/EntryControlCC.d.ts.map +1 -1
- package/build/esm/cc/EntryControlCC.js +4 -3
- package/build/esm/cc/EntryControlCC.js.map +1 -1
- package/build/esm/cc/IndicatorCC.d.ts.map +1 -1
- package/build/esm/cc/IndicatorCC.js +4 -6
- package/build/esm/cc/IndicatorCC.js.map +1 -1
- package/build/esm/cc/IrrigationCC.js.map +1 -1
- package/build/esm/cc/LanguageCC.d.ts.map +1 -1
- package/build/esm/cc/LanguageCC.js +8 -3
- package/build/esm/cc/LanguageCC.js.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.d.ts.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.js +2 -2
- package/build/esm/cc/ManufacturerSpecificCC.js.map +1 -1
- package/build/esm/cc/MeterCC.d.ts.map +1 -1
- package/build/esm/cc/MeterCC.js +27 -5
- package/build/esm/cc/MeterCC.js.map +1 -1
- package/build/esm/cc/NodeNamingCC.d.ts.map +1 -1
- package/build/esm/cc/NodeNamingCC.js +3 -3
- package/build/esm/cc/NodeNamingCC.js.map +1 -1
- package/build/esm/cc/NotificationCC.d.ts.map +1 -1
- package/build/esm/cc/NotificationCC.js +22 -24
- package/build/esm/cc/NotificationCC.js.map +1 -1
- package/build/esm/cc/Security2CC.d.ts.map +1 -1
- package/build/esm/cc/Security2CC.js +21 -10
- package/build/esm/cc/Security2CC.js.map +1 -1
- package/build/esm/cc/SecurityCC.d.ts.map +1 -1
- package/build/esm/cc/SecurityCC.js +4 -4
- package/build/esm/cc/SecurityCC.js.map +1 -1
- package/build/esm/cc/SoundSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/SoundSwitchCC.js +2 -2
- package/build/esm/cc/SoundSwitchCC.js.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.js +5 -1
- package/build/esm/cc/ThermostatSetpointCC.js.map +1 -1
- package/build/esm/cc/UserCredentialCC.d.ts +6 -0
- package/build/esm/cc/UserCredentialCC.d.ts.map +1 -1
- package/build/esm/cc/UserCredentialCC.js +103 -13
- package/build/esm/cc/UserCredentialCC.js.map +1 -1
- package/build/esm/lib/Security2/Extension.d.ts.map +1 -1
- package/build/esm/lib/Security2/Extension.js +3 -3
- package/build/esm/lib/Security2/Extension.js.map +1 -1
- package/build/esm/lib/securityLogging.d.ts +6 -0
- package/build/esm/lib/securityLogging.d.ts.map +1 -0
- package/build/esm/lib/securityLogging.js +10 -0
- package/build/esm/lib/securityLogging.js.map +1 -0
- package/build/esm/lib/serializers.d.ts.map +1 -1
- package/build/esm/lib/serializers.js +4 -0
- package/build/esm/lib/serializers.js.map +1 -1
- package/package.json +7 -7
|
@@ -2,7 +2,7 @@ import { __esDecorate, __runInitializers } from "tslib";
|
|
|
2
2
|
import * as __validateArgs from "./UserCredentialCC._validateArgs.js";
|
|
3
3
|
const { validateArgs_UserCredentialCCAPI_setUser, validateArgs_UserCredentialCCAPI_getUser, validateArgs_UserCredentialCCAPI_setCredential, validateArgs_UserCredentialCCAPI_getCredential, validateArgs_UserCredentialCCAPI_startCredentialLearn, validateArgs_UserCredentialCCAPI_setUserCredentialAssociation, validateArgs_UserCredentialCCAPI_getUserChecksum, validateArgs_UserCredentialCCAPI_getCredentialChecksum, validateArgs_UserCredentialCCAPI_setAdminPinCode, validateArgs_UserCredentialCCAPI_setKeyLockerEntry, validateArgs_UserCredentialCCAPI_getKeyLockerEntry, validateArgs_UserCredentialCCAPI_sendUserCapabilitiesReport, validateArgs_UserCredentialCCAPI_sendCredentialCapabilitiesReport, validateArgs_UserCredentialCCAPI_sendKeyLockerCapabilitiesReport, validateArgs_UserCredentialCCAPI_sendUserReport, validateArgs_UserCredentialCCAPI_sendCredentialReport, validateArgs_UserCredentialCCAPI_sendCredentialLearnReport, validateArgs_UserCredentialCCAPI_sendUserCredentialAssociationReport, validateArgs_UserCredentialCCAPI_sendAllUsersChecksumReport, validateArgs_UserCredentialCCAPI_sendUserChecksumReport, validateArgs_UserCredentialCCAPI_sendCredentialChecksumReport, validateArgs_UserCredentialCCAPI_sendAdminPinCodeReport, validateArgs_UserCredentialCCAPI_sendKeyLockerEntryReport } = __validateArgs;
|
|
4
4
|
import { CommandClasses, MessagePriority, ZWaveError, ZWaveErrorCodes, encodeBitMask, parseBitMask, validatePayload, } from "@zwave-js/core";
|
|
5
|
-
import { Bytes, getEnumMemberName, pick, stringToUint8ArrayUTF16BE, uint8ArrayToStringUTF16BE, } from "@zwave-js/shared";
|
|
5
|
+
import { Bytes, stripControlCharacters, getEnumMemberName, pick, stringToUint8ArrayUTF16BE, uint8ArrayToStringUTF16BE, } from "@zwave-js/shared";
|
|
6
6
|
import { CCAPI, PhysicalCCAPI } from "../lib/API.js";
|
|
7
7
|
import { CommandClass, getEffectiveCCVersion, } from "../lib/CommandClass.js";
|
|
8
8
|
import { API, CCCommand, ccValueProperty, ccValues, commandClass, expectedCCResponse, implementedVersion, useSupervision, } from "../lib/CommandClassDecorators.js";
|
|
@@ -18,12 +18,30 @@ function credentialToLogString(credential) {
|
|
|
18
18
|
* credentials (biometric data, BLE/NFC/RFID identifiers, ...) as raw bytes.
|
|
19
19
|
*/
|
|
20
20
|
export function normalizeCredentialData(credentialType, credentialData) {
|
|
21
|
-
if (credentialType === UserCredentialType.PINCode
|
|
22
|
-
|| credentialType === UserCredentialType.Password) {
|
|
21
|
+
if (credentialType === UserCredentialType.PINCode) {
|
|
23
22
|
return credentialData.toString("utf8");
|
|
24
23
|
}
|
|
24
|
+
if (credentialType === UserCredentialType.Password) {
|
|
25
|
+
// Passwords are UTF-16BE on the wire (CC:0083.01.0A.11.021). Received
|
|
26
|
+
// commands with an odd length are rejected when they are parsed.
|
|
27
|
+
return uint8ArrayToStringUTF16BE(credentialData);
|
|
28
|
+
}
|
|
25
29
|
return credentialData;
|
|
26
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Converts a credential to the bytes transmitted to the node. Strings are
|
|
33
|
+
* encoded according to the credential type, the inverse of
|
|
34
|
+
* {@link normalizeCredentialData}.
|
|
35
|
+
*/
|
|
36
|
+
export function encodeCredentialData(credentialType, credentialData) {
|
|
37
|
+
if (typeof credentialData !== "string")
|
|
38
|
+
return Bytes.from(credentialData);
|
|
39
|
+
if (credentialType === UserCredentialType.Password) {
|
|
40
|
+
// CC:0083.01.0A.11.021
|
|
41
|
+
return Bytes.from(stringToUint8ArrayUTF16BE(credentialData));
|
|
42
|
+
}
|
|
43
|
+
return Bytes.from(credentialData, "utf-8");
|
|
44
|
+
}
|
|
27
45
|
import { UserCredentialCCValues } from "./_CCValues.generated.js";
|
|
28
46
|
export { UserCredentialCCValues };
|
|
29
47
|
// API class
|
|
@@ -213,6 +231,20 @@ let UserCredentialCCAPI = (() => {
|
|
|
213
231
|
*/
|
|
214
232
|
async setUser(options) {
|
|
215
233
|
this.assertSupportsCommand(UserCredentialCommand, UserCredentialCommand.UserSet);
|
|
234
|
+
if (options.operationType !== UserCredentialOperationType.Delete
|
|
235
|
+
&& options.nameEncoding == undefined) {
|
|
236
|
+
const userName = options.userName ?? "";
|
|
237
|
+
const supportedEncodings = this.tryGetValueDB()?.getValue(UserCredentialCCValues.supportedUserNameEncodings.endpoint(this.endpoint.index)) ?? [
|
|
238
|
+
UserCredentialNameEncoding.ASCII,
|
|
239
|
+
UserCredentialNameEncoding.ExtendedASCII,
|
|
240
|
+
UserCredentialNameEncoding.UTF16BE,
|
|
241
|
+
];
|
|
242
|
+
const nameEncoding = chooseNameEncoding(userName, supportedEncodings);
|
|
243
|
+
if (nameEncoding == undefined) {
|
|
244
|
+
throw new ZWaveError(`The user name "${userName}" cannot be encoded with any of the encodings supported by the node`, ZWaveErrorCodes.Argument_Invalid);
|
|
245
|
+
}
|
|
246
|
+
options = { ...options, nameEncoding };
|
|
247
|
+
}
|
|
216
248
|
const cc = new UserCredentialCCUserSet({
|
|
217
249
|
nodeId: this.endpoint.nodeId,
|
|
218
250
|
endpointIndex: this.endpoint.index,
|
|
@@ -1179,6 +1211,43 @@ function testResponseForUserCredentialUserSet(sent, received) {
|
|
|
1179
1211
|
return (received.reportType !== UserCredentialUserReportType.ResponseToGet
|
|
1180
1212
|
&& received.userId === sent.userId);
|
|
1181
1213
|
}
|
|
1214
|
+
// ASCII and Extended ASCII user names use a single byte per character, so they are
|
|
1215
|
+
// interpreted as ISO-8859-1, whose code points match the byte values
|
|
1216
|
+
function decodeSingleByteName(data) {
|
|
1217
|
+
return String.fromCharCode(...data);
|
|
1218
|
+
}
|
|
1219
|
+
function encodeSingleByteName(name, encoding) {
|
|
1220
|
+
const maxCharCode = encoding === UserCredentialNameEncoding.ExtendedASCII ? 0xff : 0x7f;
|
|
1221
|
+
const ret = new Bytes(name.length);
|
|
1222
|
+
for (let i = 0; i < name.length; i++) {
|
|
1223
|
+
const code = name.charCodeAt(i);
|
|
1224
|
+
if (code > maxCharCode) {
|
|
1225
|
+
throw new ZWaveError(`The user name "${name}" cannot be encoded as ${encoding === UserCredentialNameEncoding.ExtendedASCII
|
|
1226
|
+
? "Extended ASCII"
|
|
1227
|
+
: "ASCII"}`, ZWaveErrorCodes.Argument_Invalid);
|
|
1228
|
+
}
|
|
1229
|
+
ret[i] = code;
|
|
1230
|
+
}
|
|
1231
|
+
return ret;
|
|
1232
|
+
}
|
|
1233
|
+
/** Returns the most compact encoding out of `supported` that can represent the user name */
|
|
1234
|
+
function chooseNameEncoding(name, supported) {
|
|
1235
|
+
let maxCharCode = 0;
|
|
1236
|
+
for (let i = 0; i < name.length; i++) {
|
|
1237
|
+
maxCharCode = Math.max(maxCharCode, name.charCodeAt(i));
|
|
1238
|
+
}
|
|
1239
|
+
if (maxCharCode <= 0x7f
|
|
1240
|
+
&& supported.includes(UserCredentialNameEncoding.ASCII)) {
|
|
1241
|
+
return UserCredentialNameEncoding.ASCII;
|
|
1242
|
+
}
|
|
1243
|
+
else if (maxCharCode <= 0xff
|
|
1244
|
+
&& supported.includes(UserCredentialNameEncoding.ExtendedASCII)) {
|
|
1245
|
+
return UserCredentialNameEncoding.ExtendedASCII;
|
|
1246
|
+
}
|
|
1247
|
+
else if (supported.includes(UserCredentialNameEncoding.UTF16BE)) {
|
|
1248
|
+
return UserCredentialNameEncoding.UTF16BE;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1182
1251
|
let UserCredentialCCUserSet = (() => {
|
|
1183
1252
|
let _classDecorators = [CCCommand(UserCredentialCommand.UserSet), expectedCCResponse(() => UserCredentialCCUserReport, testResponseForUserCredentialUserSet)];
|
|
1184
1253
|
let _classDescriptor;
|
|
@@ -1243,13 +1312,13 @@ let UserCredentialCCUserSet = (() => {
|
|
|
1243
1312
|
validatePayload(raw.payload.length >= 10 + nameLength);
|
|
1244
1313
|
let userName;
|
|
1245
1314
|
if (nameEncoding === UserCredentialNameEncoding.UTF16BE) {
|
|
1315
|
+
validatePayload(nameLength % 2 === 0);
|
|
1246
1316
|
userName = uint8ArrayToStringUTF16BE(raw.payload.subarray(10, 10 + nameLength));
|
|
1247
1317
|
}
|
|
1248
1318
|
else {
|
|
1249
|
-
userName = raw.payload
|
|
1250
|
-
.subarray(10, 10 + nameLength)
|
|
1251
|
-
.toString("ascii");
|
|
1319
|
+
userName = decodeSingleByteName(raw.payload.subarray(10, 10 + nameLength));
|
|
1252
1320
|
}
|
|
1321
|
+
userName = stripControlCharacters(userName);
|
|
1253
1322
|
if (userType === UserCredentialUserType.Expiring) {
|
|
1254
1323
|
return new this({
|
|
1255
1324
|
nodeId: ctx.sourceNodeId,
|
|
@@ -1288,6 +1357,9 @@ let UserCredentialCCUserSet = (() => {
|
|
|
1288
1357
|
if (this.active == undefined) {
|
|
1289
1358
|
throw new ZWaveError(`${this.constructor.name}: The active flag must be set for Add/Modify operations`, ZWaveErrorCodes.Argument_Invalid);
|
|
1290
1359
|
}
|
|
1360
|
+
if (this.nameEncoding == undefined) {
|
|
1361
|
+
throw new ZWaveError(`${this.constructor.name}: name encoding must be set for Add/Modify operations`, ZWaveErrorCodes.Argument_Invalid);
|
|
1362
|
+
}
|
|
1291
1363
|
// Credential rule defaults to Single
|
|
1292
1364
|
const credentialRule = this.credentialRule ?? UserCredentialRule.Single;
|
|
1293
1365
|
// Expiring timeout MUST be 0 for non-Expiring user types
|
|
@@ -1301,16 +1373,18 @@ let UserCredentialCCUserSet = (() => {
|
|
|
1301
1373
|
else {
|
|
1302
1374
|
expiringTimeoutMinutes = 0;
|
|
1303
1375
|
}
|
|
1304
|
-
// Name encoding defaults to ASCII
|
|
1305
|
-
const nameEncoding = this.nameEncoding ?? UserCredentialNameEncoding.ASCII;
|
|
1306
1376
|
// User name defaults to empty string
|
|
1307
1377
|
const userName = this.userName ?? "";
|
|
1378
|
+
const nameEncoding = this.nameEncoding;
|
|
1308
1379
|
let nameBuffer;
|
|
1309
1380
|
if (nameEncoding === UserCredentialNameEncoding.UTF16BE) {
|
|
1310
1381
|
nameBuffer = stringToUint8ArrayUTF16BE(userName);
|
|
1311
1382
|
}
|
|
1383
|
+
else if (nameEncoding === UserCredentialNameEncoding.ExtendedASCII) {
|
|
1384
|
+
nameBuffer = encodeSingleByteName(userName, UserCredentialNameEncoding.ExtendedASCII);
|
|
1385
|
+
}
|
|
1312
1386
|
else {
|
|
1313
|
-
nameBuffer =
|
|
1387
|
+
nameBuffer = encodeSingleByteName(userName, UserCredentialNameEncoding.ASCII);
|
|
1314
1388
|
}
|
|
1315
1389
|
this.payload = Bytes.alloc(10 + nameBuffer.length);
|
|
1316
1390
|
this.payload[0] = this.operationType & 0b11;
|
|
@@ -1403,13 +1477,13 @@ let UserCredentialCCUserReport = (() => {
|
|
|
1403
1477
|
validatePayload(raw.payload.length >= 15 + nameLength);
|
|
1404
1478
|
let userName;
|
|
1405
1479
|
if (nameEncoding === UserCredentialNameEncoding.UTF16BE) {
|
|
1480
|
+
validatePayload(nameLength % 2 === 0);
|
|
1406
1481
|
userName = uint8ArrayToStringUTF16BE(raw.payload.subarray(15, 15 + nameLength));
|
|
1407
1482
|
}
|
|
1408
1483
|
else {
|
|
1409
|
-
userName = raw.payload
|
|
1410
|
-
.subarray(15, 15 + nameLength)
|
|
1411
|
-
.toString("ascii");
|
|
1484
|
+
userName = decodeSingleByteName(raw.payload.subarray(15, 15 + nameLength));
|
|
1412
1485
|
}
|
|
1486
|
+
userName = stripControlCharacters(userName);
|
|
1413
1487
|
const common = {
|
|
1414
1488
|
nodeId: ctx.sourceNodeId,
|
|
1415
1489
|
modifierType,
|
|
@@ -1443,8 +1517,11 @@ let UserCredentialCCUserReport = (() => {
|
|
|
1443
1517
|
if (this.nameEncoding === UserCredentialNameEncoding.UTF16BE) {
|
|
1444
1518
|
nameBuffer = stringToUint8ArrayUTF16BE(this.userName);
|
|
1445
1519
|
}
|
|
1520
|
+
else if (this.nameEncoding === UserCredentialNameEncoding.ExtendedASCII) {
|
|
1521
|
+
nameBuffer = encodeSingleByteName(this.userName, UserCredentialNameEncoding.ExtendedASCII);
|
|
1522
|
+
}
|
|
1446
1523
|
else {
|
|
1447
|
-
nameBuffer =
|
|
1524
|
+
nameBuffer = encodeSingleByteName(this.userName, UserCredentialNameEncoding.ASCII);
|
|
1448
1525
|
}
|
|
1449
1526
|
this.payload = Bytes.alloc(15 + nameBuffer.length);
|
|
1450
1527
|
this.payload[0] = this.reportType;
|
|
@@ -1690,6 +1767,9 @@ let UserCredentialCCCredentialSet = (() => {
|
|
|
1690
1767
|
if (raw.payload.length >= 7) {
|
|
1691
1768
|
const credentialLength = raw.payload[6];
|
|
1692
1769
|
validatePayload(raw.payload.length >= 7 + credentialLength);
|
|
1770
|
+
// Passwords are UTF-16BE (CC:0083.01.0A.11.021)
|
|
1771
|
+
validatePayload(credentialType !== UserCredentialType.Password
|
|
1772
|
+
|| credentialLength % 2 === 0);
|
|
1693
1773
|
credentialData = Bytes.from(raw.payload.subarray(7, 7 + credentialLength));
|
|
1694
1774
|
}
|
|
1695
1775
|
return new this({
|
|
@@ -1783,6 +1863,16 @@ let UserCredentialCCCredentialReport = (() => {
|
|
|
1783
1863
|
const credentialReadBack = !!(raw.payload[6] & 128);
|
|
1784
1864
|
const credentialLength = raw.payload[7];
|
|
1785
1865
|
validatePayload(raw.payload.length >= 8 + credentialLength + 6);
|
|
1866
|
+
if (credentialType === UserCredentialType.Password
|
|
1867
|
+
&& credentialLength % 2 !== 0) {
|
|
1868
|
+
// CC:0083.01.0C.11.000: If the credential cannot be read back
|
|
1869
|
+
// (CRB is zero), the node MUST instead report a hash sum of the credential.
|
|
1870
|
+
if (credentialReadBack) {
|
|
1871
|
+
// CC:0083.01.0A.11.021: Passwords MUST be transmitted in Unicode
|
|
1872
|
+
// UTF-16 format, in big endian order.
|
|
1873
|
+
validatePayload.fail("Password credentials must have an even length");
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1786
1876
|
const offset = 8 + credentialLength;
|
|
1787
1877
|
const modifierType = raw.payload[offset];
|
|
1788
1878
|
const modifierNodeId = raw.payload.readUInt16BE(offset + 1);
|