@zwave-js/cc 10.0.0-beta.1 → 10.0.0-beta.11
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/cc/AlarmSensorCC.d.ts +2 -2
- package/build/cc/AssociationCC.d.ts +8 -8
- package/build/cc/AssociationCC.d.ts.map +1 -1
- package/build/cc/AssociationCC.js +7 -4
- package/build/cc/AssociationCC.js.map +1 -1
- package/build/cc/AssociationGroupInfoCC.d.ts +4 -4
- package/build/cc/BarrierOperatorCC.d.ts +2 -2
- package/build/cc/BarrierOperatorCC.d.ts.map +1 -1
- package/build/cc/BarrierOperatorCC.js +9 -3
- package/build/cc/BarrierOperatorCC.js.map +1 -1
- package/build/cc/BasicCC.d.ts +1 -1
- package/build/cc/BatteryCC.d.ts +10 -10
- package/build/cc/BinarySensorCC.d.ts +1 -1
- package/build/cc/BinarySwitchCC.d.ts +1 -1
- package/build/cc/CRC16CC.d.ts +3 -1
- package/build/cc/CRC16CC.d.ts.map +1 -1
- package/build/cc/CRC16CC.js +11 -1
- package/build/cc/CRC16CC.js.map +1 -1
- package/build/cc/CentralSceneCC.d.ts +5 -5
- package/build/cc/CentralSceneCC.d.ts.map +1 -1
- package/build/cc/CentralSceneCC.js +4 -4
- package/build/cc/CentralSceneCC.js.map +1 -1
- package/build/cc/ClimateControlScheduleCC.d.ts +3 -3
- package/build/cc/ClimateControlScheduleCC.d.ts.map +1 -1
- package/build/cc/ClimateControlScheduleCC.js +6 -4
- package/build/cc/ClimateControlScheduleCC.js.map +1 -1
- package/build/cc/ClockCC.d.ts +2 -2
- package/build/cc/ClockCC.d.ts.map +1 -1
- package/build/cc/ClockCC.js +3 -2
- package/build/cc/ClockCC.js.map +1 -1
- package/build/cc/ColorSwitchCC.d.ts +2 -2
- package/build/cc/ColorSwitchCC.d.ts.map +1 -1
- package/build/cc/ColorSwitchCC.js +3 -4
- package/build/cc/ColorSwitchCC.js.map +1 -1
- package/build/cc/ConfigurationCC.d.ts.map +1 -1
- package/build/cc/ConfigurationCC.js +6 -5
- package/build/cc/ConfigurationCC.js.map +1 -1
- package/build/cc/DoorLockCC.d.ts +14 -14
- package/build/cc/DoorLockCC.d.ts.map +1 -1
- package/build/cc/DoorLockCC.js +3 -1
- package/build/cc/DoorLockCC.js.map +1 -1
- package/build/cc/DoorLockLoggingCC.d.ts +1 -1
- package/build/cc/EntryControlCC.d.ts +5 -6
- package/build/cc/EntryControlCC.d.ts.map +1 -1
- package/build/cc/EntryControlCC.js +20 -11
- package/build/cc/EntryControlCC.js.map +1 -1
- package/build/cc/FirmwareUpdateMetaDataCC.d.ts +4 -4
- package/build/cc/HumidityControlModeCC.d.ts +1 -1
- package/build/cc/HumidityControlSetpointCC.d.ts +1 -1
- package/build/cc/IndicatorCC.d.ts +6 -6
- package/build/cc/IndicatorCC.d.ts.map +1 -1
- package/build/cc/IndicatorCC.js +6 -6
- package/build/cc/IndicatorCC.js.map +1 -1
- package/build/cc/IrrigationCC.d.ts +7 -7
- package/build/cc/IrrigationCC.d.ts.map +1 -1
- package/build/cc/IrrigationCC.js +11 -8
- package/build/cc/IrrigationCC.js.map +1 -1
- package/build/cc/LanguageCC.d.ts +2 -2
- package/build/cc/LanguageCC.d.ts.map +1 -1
- package/build/cc/LanguageCC.js +3 -2
- package/build/cc/LanguageCC.js.map +1 -1
- package/build/cc/ManufacturerSpecificCC.d.ts +1 -1
- package/build/cc/MeterCC.d.ts +6 -6
- package/build/cc/MeterCC.d.ts.map +1 -1
- package/build/cc/MeterCC.js +3 -2
- package/build/cc/MeterCC.js.map +1 -1
- package/build/cc/MultiChannelAssociationCC.d.ts +7 -7
- package/build/cc/MultiChannelAssociationCC.d.ts.map +1 -1
- package/build/cc/MultiChannelAssociationCC.js +5 -3
- package/build/cc/MultiChannelAssociationCC.js.map +1 -1
- package/build/cc/MultiChannelCC.d.ts +3 -3
- package/build/cc/MultiChannelCC.d.ts.map +1 -1
- package/build/cc/MultiChannelCC.js +7 -6
- package/build/cc/MultiChannelCC.js.map +1 -1
- package/build/cc/MultiCommandCC.d.ts +0 -1
- package/build/cc/MultiCommandCC.d.ts.map +1 -1
- package/build/cc/MultiCommandCC.js +10 -4
- package/build/cc/MultiCommandCC.js.map +1 -1
- package/build/cc/MultilevelSensorCC.d.ts +4 -4
- package/build/cc/MultilevelSensorCC.d.ts.map +1 -1
- package/build/cc/MultilevelSensorCC.js +3 -2
- package/build/cc/MultilevelSensorCC.js.map +1 -1
- package/build/cc/MultilevelSwitchCC.d.ts +2 -2
- package/build/cc/NodeNamingCC.d.ts +3 -3
- package/build/cc/NodeNamingCC.d.ts.map +1 -1
- package/build/cc/NodeNamingCC.js +8 -8
- package/build/cc/NodeNamingCC.js.map +1 -1
- package/build/cc/NotificationCC.d.ts +3 -3
- package/build/cc/NotificationCC.d.ts.map +1 -1
- package/build/cc/NotificationCC.js +11 -6
- package/build/cc/NotificationCC.js.map +1 -1
- package/build/cc/PowerlevelCC.d.ts +4 -4
- package/build/cc/PowerlevelCC.d.ts.map +1 -1
- package/build/cc/PowerlevelCC.js +7 -5
- package/build/cc/PowerlevelCC.js.map +1 -1
- package/build/cc/ProtectionCC.d.ts +7 -7
- package/build/cc/SceneActivationCC.d.ts +3 -3
- package/build/cc/SceneActivationCC.d.ts.map +1 -1
- package/build/cc/SceneActivationCC.js +4 -4
- package/build/cc/SceneActivationCC.js.map +1 -1
- package/build/cc/SceneActuatorConfigurationCC.d.ts +2 -2
- package/build/cc/SceneActuatorConfigurationCC.d.ts.map +1 -1
- package/build/cc/SceneActuatorConfigurationCC.js +5 -5
- package/build/cc/SceneActuatorConfigurationCC.js.map +1 -1
- package/build/cc/SceneControllerConfigurationCC.d.ts +3 -3
- package/build/cc/SceneControllerConfigurationCC.d.ts.map +1 -1
- package/build/cc/SceneControllerConfigurationCC.js +6 -6
- package/build/cc/SceneControllerConfigurationCC.js.map +1 -1
- package/build/cc/Security2CC.d.ts +2 -1
- package/build/cc/Security2CC.d.ts.map +1 -1
- package/build/cc/Security2CC.js +159 -78
- package/build/cc/Security2CC.js.map +1 -1
- package/build/cc/SecurityCC.d.ts.map +1 -1
- package/build/cc/SecurityCC.js +11 -7
- package/build/cc/SecurityCC.js.map +1 -1
- package/build/cc/SoundSwitchCC.d.ts +1 -1
- package/build/cc/SupervisionCC.d.ts +2 -5
- package/build/cc/SupervisionCC.d.ts.map +1 -1
- package/build/cc/SupervisionCC.js +15 -31
- package/build/cc/SupervisionCC.js.map +1 -1
- package/build/cc/ThermostatFanModeCC.d.ts +2 -2
- package/build/cc/ThermostatModeCC.d.ts +1 -1
- package/build/cc/ThermostatSetbackCC.d.ts +2 -2
- package/build/cc/ThermostatSetbackCC.d.ts.map +1 -1
- package/build/cc/ThermostatSetbackCC.js +3 -2
- package/build/cc/ThermostatSetbackCC.js.map +1 -1
- package/build/cc/ThermostatSetpointCC.d.ts +3 -3
- package/build/cc/TimeCC.d.ts +17 -11
- package/build/cc/TimeCC.d.ts.map +1 -1
- package/build/cc/TimeCC.js +96 -51
- package/build/cc/TimeCC.js.map +1 -1
- package/build/cc/TimeParametersCC.d.ts +2 -2
- package/build/cc/TimeParametersCC.d.ts.map +1 -1
- package/build/cc/TimeParametersCC.js +4 -4
- package/build/cc/TimeParametersCC.js.map +1 -1
- package/build/cc/UserCodeCC.d.ts +19 -19
- package/build/cc/UserCodeCC.d.ts.map +1 -1
- package/build/cc/UserCodeCC.js +47 -35
- package/build/cc/UserCodeCC.js.map +1 -1
- package/build/cc/VersionCC.d.ts +1 -1
- package/build/cc/WakeUpCC.d.ts +2 -2
- package/build/cc/WakeUpCC.d.ts.map +1 -1
- package/build/cc/WakeUpCC.js +5 -5
- package/build/cc/WakeUpCC.js.map +1 -1
- package/build/cc/ZWavePlusCC.d.ts +2 -2
- package/build/index.d.ts +2 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -4
- package/build/index.js.map +1 -1
- package/build/lib/CommandClass.d.ts +6 -11
- package/build/lib/CommandClass.d.ts.map +1 -1
- package/build/lib/CommandClass.js +14 -7
- package/build/lib/CommandClass.js.map +1 -1
- package/build/lib/Values.d.ts +2 -2
- package/build/lib/_Types.d.ts +5 -82
- package/build/lib/_Types.d.ts.map +1 -1
- package/build/lib/_Types.js.map +1 -1
- package/build/lib/serializers.d.ts +11 -1
- package/build/lib/serializers.d.ts.map +1 -1
- package/build/lib/serializers.js +42 -3
- package/build/lib/serializers.js.map +1 -1
- package/build/lib/utils.js +1 -1
- package/build/lib/utils.js.map +1 -1
- package/package.json +13 -10
package/build/cc/Security2CC.js
CHANGED
|
@@ -9,8 +9,9 @@ var Security2CC_1;
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.Security2CCCommandsSupportedGet = exports.Security2CCCommandsSupportedReport = exports.Security2CCTransferEnd = exports.Security2CCNetworkKeyVerify = exports.Security2CCNetworkKeyGet = exports.Security2CCNetworkKeyReport = exports.Security2CCPublicKeyReport = exports.Security2CCKEXFail = exports.Security2CCKEXSet = exports.Security2CCKEXGet = exports.Security2CCKEXReport = exports.Security2CCNonceGet = exports.Security2CCNonceReport = exports.Security2CCMessageEncapsulation = exports.Security2CC = exports.Security2CCAPI = void 0;
|
|
11
11
|
const core_1 = require("@zwave-js/core");
|
|
12
|
-
const
|
|
13
|
-
const
|
|
12
|
+
const safe_1 = require("@zwave-js/core/safe");
|
|
13
|
+
const safe_2 = require("@zwave-js/shared/safe");
|
|
14
|
+
const async_1 = require("alcalzone-shared/async");
|
|
14
15
|
const API_1 = require("../lib/API");
|
|
15
16
|
const CommandClass_1 = require("../lib/CommandClass");
|
|
16
17
|
const CommandClassDecorators_1 = require("../lib/CommandClassDecorators");
|
|
@@ -36,15 +37,14 @@ function getAuthenticationData(sendingNodeId, destination, homeId, commandLength
|
|
|
36
37
|
unencryptedPayload.copy(ret, 8, 0);
|
|
37
38
|
return ret;
|
|
38
39
|
}
|
|
39
|
-
/** Validates that a sequence number is not a duplicate and updates the SPAN table if it is accepted */
|
|
40
|
+
/** Validates that a sequence number is not a duplicate and updates the SPAN table if it is accepted. Returns the previous sequence number if there is one. */
|
|
40
41
|
function validateSequenceNumber(sequenceNumber) {
|
|
41
|
-
|
|
42
|
-
core_1.validatePayload.withReason("Duplicate command")(!this.host.securityManager2.isDuplicateSinglecast(peerNodeID, sequenceNumber));
|
|
42
|
+
core_1.validatePayload.withReason("Duplicate command")(!this.host.securityManager2.isDuplicateSinglecast(this.nodeId, sequenceNumber));
|
|
43
43
|
// Not a duplicate, store it
|
|
44
|
-
this.host.securityManager2.storeSequenceNumber(
|
|
44
|
+
return this.host.securityManager2.storeSequenceNumber(this.nodeId, sequenceNumber);
|
|
45
45
|
}
|
|
46
46
|
function assertSecurity(options) {
|
|
47
|
-
const verb = (0,
|
|
47
|
+
const verb = (0, CommandClass_1.gotDeserializationOptions)(options) ? "decoded" : "sent";
|
|
48
48
|
if (!this.host.ownNodeId) {
|
|
49
49
|
throw new core_1.ZWaveError(`Secure commands (S2) can only be ${verb} when the controller's node id is known!`, core_1.ZWaveErrorCodes.Driver_NotReady);
|
|
50
50
|
}
|
|
@@ -137,7 +137,7 @@ let Security2CCAPI = class Security2CCAPI extends API_1.CCAPI {
|
|
|
137
137
|
});
|
|
138
138
|
const response = await this.applHost.sendCommand(cc, this.commandOptions);
|
|
139
139
|
if (response) {
|
|
140
|
-
return (0,
|
|
140
|
+
return (0, safe_2.pick)(response, [
|
|
141
141
|
"requestCSA",
|
|
142
142
|
"echo",
|
|
143
143
|
"supportedKEXSchemes",
|
|
@@ -224,7 +224,7 @@ let Security2CC = Security2CC_1 = class Security2CC extends CommandClass_1.Comma
|
|
|
224
224
|
const api = API_1.CCAPI.create(core_1.CommandClasses["Security 2"], applHost, endpoint).withOptions({
|
|
225
225
|
priority: core_1.MessagePriority.NodeQuery,
|
|
226
226
|
});
|
|
227
|
-
// Only on the highest security class the
|
|
227
|
+
// Only on the highest security class the response includes the supported commands
|
|
228
228
|
const secClass = node.getHighestSecurityClass();
|
|
229
229
|
let hasReceivedSecureCommands = false;
|
|
230
230
|
let possibleSecurityClasses;
|
|
@@ -263,54 +263,85 @@ let Security2CC = Security2CC_1 = class Security2CC extends CommandClass_1.Comma
|
|
|
263
263
|
if (!this.host.securityManager2?.hasKeysForSecurityClass(secClass)) {
|
|
264
264
|
applHost.controllerLog.logNode(node.id, {
|
|
265
265
|
endpoint: endpoint.index,
|
|
266
|
-
message: `Cannot query securely supported commands (${(0,
|
|
266
|
+
message: `Cannot query securely supported commands (${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)}) - network key is not configured...`,
|
|
267
267
|
level: "warn",
|
|
268
268
|
});
|
|
269
269
|
continue;
|
|
270
270
|
}
|
|
271
271
|
applHost.controllerLog.logNode(node.id, {
|
|
272
272
|
endpoint: endpoint.index,
|
|
273
|
-
message: `Querying securely supported commands (${(0,
|
|
273
|
+
message: `Querying securely supported commands (${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)})...`,
|
|
274
274
|
direction: "outbound",
|
|
275
275
|
});
|
|
276
276
|
// Query the supported commands but avoid remembering the wrong security class in case of a failure
|
|
277
277
|
let supportedCCs;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
278
|
+
// Try up to 3 times. We REALLY don't want a spurious timeout or collision to cause us to discard a known good security class
|
|
279
|
+
for (let attempts = 1; attempts <= 3; attempts++) {
|
|
280
|
+
try {
|
|
281
|
+
supportedCCs = await api.getSupportedCommands(secClass);
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
if ((0, core_1.isZWaveError)(e) &&
|
|
285
|
+
e.code === core_1.ZWaveErrorCodes.Security2CC_CannotDecode) {
|
|
286
|
+
// Either we were using a non-granted security class,
|
|
287
|
+
// or querying with the known highest security class had an issue
|
|
288
|
+
supportedCCs = undefined;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
throw e;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (supportedCCs == undefined &&
|
|
295
|
+
possibleSecurityClasses.length === 1) {
|
|
296
|
+
if (attempts < 3) {
|
|
297
|
+
// We definitely know the highest security class
|
|
298
|
+
applHost.controllerLog.logNode(node.id, {
|
|
299
|
+
endpoint: endpoint.index,
|
|
300
|
+
message: `Querying securely supported commands (${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)}), attempt ${attempts}/3 failed. Retrying in 500ms...`,
|
|
301
|
+
level: "warn",
|
|
302
|
+
});
|
|
303
|
+
await (0, async_1.wait)(500);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
applHost.controllerLog.logNode(node.id, {
|
|
308
|
+
endpoint: endpoint.index,
|
|
309
|
+
message: `Querying securely supported commands (${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)}) failed. Let's hope for the best...`,
|
|
310
|
+
level: "warn",
|
|
311
|
+
});
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
286
314
|
}
|
|
287
315
|
else {
|
|
288
|
-
|
|
316
|
+
// In any other case, we can stop trying
|
|
317
|
+
break;
|
|
289
318
|
}
|
|
290
319
|
}
|
|
291
320
|
if (supportedCCs == undefined) {
|
|
292
|
-
if (endpoint.index === 0
|
|
321
|
+
if (endpoint.index === 0 &&
|
|
322
|
+
possibleSecurityClasses.length > 1) {
|
|
293
323
|
// No supported commands found, mark the security class as not granted
|
|
324
|
+
// unless we were sure about the security class
|
|
294
325
|
node.setSecurityClass(secClass, false);
|
|
295
326
|
applHost.controllerLog.logNode(node.id, {
|
|
296
|
-
message: `The node was NOT granted the security class ${(0,
|
|
327
|
+
message: `The node was NOT granted the security class ${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)}`,
|
|
297
328
|
direction: "inbound",
|
|
298
329
|
});
|
|
299
330
|
}
|
|
300
331
|
continue;
|
|
301
332
|
}
|
|
302
|
-
if (endpoint.index === 0) {
|
|
303
|
-
// Mark the security class as granted
|
|
333
|
+
if (endpoint.index === 0 && possibleSecurityClasses.length > 1) {
|
|
334
|
+
// Mark the security class as granted unless we were sure about the security class
|
|
304
335
|
node.setSecurityClass(secClass, true);
|
|
305
336
|
applHost.controllerLog.logNode(node.id, {
|
|
306
|
-
message: `The node was granted the security class ${(0,
|
|
337
|
+
message: `The node was granted the security class ${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)}`,
|
|
307
338
|
direction: "inbound",
|
|
308
339
|
});
|
|
309
340
|
}
|
|
310
341
|
if (!hasReceivedSecureCommands && supportedCCs.length > 0) {
|
|
311
342
|
hasReceivedSecureCommands = true;
|
|
312
343
|
const logLines = [
|
|
313
|
-
`received secure commands (${(0,
|
|
344
|
+
`received secure commands (${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, secClass)})`,
|
|
314
345
|
"supported CCs:",
|
|
315
346
|
];
|
|
316
347
|
for (const cc of supportedCCs) {
|
|
@@ -336,8 +367,9 @@ let Security2CC = Security2CC_1 = class Security2CC extends CommandClass_1.Comma
|
|
|
336
367
|
/** Tests if a command should be sent secure and thus requires encapsulation */
|
|
337
368
|
static requiresEncapsulation(cc) {
|
|
338
369
|
// Everything that's not an S2 CC needs to be encapsulated if the CC is secure
|
|
339
|
-
if (!cc.
|
|
370
|
+
if (!(cc.encapsulationFlags & safe_1.EncapsulationFlags.Security)) {
|
|
340
371
|
return false;
|
|
372
|
+
}
|
|
341
373
|
if (!(cc instanceof Security2CC_1))
|
|
342
374
|
return true;
|
|
343
375
|
// These S2 commands need additional encapsulation
|
|
@@ -369,11 +401,16 @@ let Security2CC = Security2CC_1 = class Security2CC extends CommandClass_1.Comma
|
|
|
369
401
|
}
|
|
370
402
|
/** Encapsulates a command that should be sent encrypted */
|
|
371
403
|
static encapsulate(host, cc, securityClass) {
|
|
372
|
-
|
|
404
|
+
const ret = new Security2CCMessageEncapsulation(host, {
|
|
373
405
|
nodeId: cc.nodeId,
|
|
374
406
|
encapsulated: cc,
|
|
375
407
|
securityClass,
|
|
376
408
|
});
|
|
409
|
+
// Copy the encapsulation flags from the encapsulated command
|
|
410
|
+
// but omit Security, since we're doing that right now
|
|
411
|
+
ret.encapsulationFlags =
|
|
412
|
+
cc.encapsulationFlags & ~safe_1.EncapsulationFlags.Security;
|
|
413
|
+
return ret;
|
|
377
414
|
}
|
|
378
415
|
};
|
|
379
416
|
Security2CC = Security2CC_1 = __decorate([
|
|
@@ -403,18 +440,18 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
403
440
|
super(host, options);
|
|
404
441
|
// Make sure that we can send/receive secure commands
|
|
405
442
|
assertSecurity.call(this, options);
|
|
406
|
-
if ((0,
|
|
443
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
407
444
|
(0, core_1.validatePayload)(this.payload.length >= 2);
|
|
408
445
|
// Check the sequence number to avoid duplicates
|
|
409
446
|
// TODO: distinguish between multicast and singlecast
|
|
410
447
|
this._sequenceNumber = this.payload[0];
|
|
448
|
+
const sendingNodeId = this.nodeId;
|
|
411
449
|
// Don't accept duplicate commands
|
|
412
|
-
validateSequenceNumber.call(this, this._sequenceNumber);
|
|
450
|
+
const prevSequenceNumber = validateSequenceNumber.call(this, this._sequenceNumber);
|
|
413
451
|
// Ensure the node has a security class
|
|
414
|
-
const peerNodeID = this.nodeId;
|
|
415
452
|
// const node = this.getNode()!;
|
|
416
453
|
// validatePayload.withReason("The node is not included")(!!node);
|
|
417
|
-
const securityClass = this.host.getHighestSecurityClass(
|
|
454
|
+
const securityClass = this.host.getHighestSecurityClass(sendingNodeId);
|
|
418
455
|
core_1.validatePayload.withReason("No security class granted")(securityClass !== core_1.SecurityClass.None);
|
|
419
456
|
const hasExtensions = !!(this.payload[1] & 0b1);
|
|
420
457
|
const hasEncryptedExtensions = !!(this.payload[1] & 0b10);
|
|
@@ -440,9 +477,9 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
440
477
|
const ciphertext = this.payload.slice(offset, -core_1.SECURITY_S2_AUTH_TAG_LENGTH);
|
|
441
478
|
const authTag = this.payload.slice(-core_1.SECURITY_S2_AUTH_TAG_LENGTH);
|
|
442
479
|
const messageLength = super.computeEncapsulationOverhead() + this.payload.length;
|
|
443
|
-
const authData = getAuthenticationData(
|
|
480
|
+
const authData = getAuthenticationData(sendingNodeId, this.getDestinationIDRX(), this.host.homeId, messageLength, unencryptedPayload);
|
|
444
481
|
// Decrypt payload and verify integrity
|
|
445
|
-
const spanState = this.host.securityManager2.getSPANState(
|
|
482
|
+
const spanState = this.host.securityManager2.getSPANState(sendingNodeId);
|
|
446
483
|
const failNoSPAN = () => {
|
|
447
484
|
return core_1.validatePayload.fail(core_1.ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
448
485
|
};
|
|
@@ -456,15 +493,43 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
456
493
|
return failNoSPAN();
|
|
457
494
|
}
|
|
458
495
|
const decrypt = () => {
|
|
459
|
-
const
|
|
460
|
-
const
|
|
461
|
-
const
|
|
496
|
+
const decryptWithNonce = (nonce) => {
|
|
497
|
+
const { keyCCM: key } = this.host.securityManager2.getKeysForNode(sendingNodeId);
|
|
498
|
+
const iv = nonce;
|
|
462
499
|
return {
|
|
463
|
-
|
|
500
|
+
key,
|
|
501
|
+
iv,
|
|
464
502
|
...(0, core_1.decryptAES128CCM)(key, iv, ciphertext, authData, authTag),
|
|
465
503
|
};
|
|
466
504
|
};
|
|
505
|
+
const getNonceAndDecrypt = () => {
|
|
506
|
+
const iv = this.host.securityManager2.nextNonce(sendingNodeId);
|
|
507
|
+
return decryptWithNonce(iv);
|
|
508
|
+
};
|
|
467
509
|
if (spanState.type === core_1.SPANState.SPAN) {
|
|
510
|
+
// There SHOULD be a shared SPAN between both parties. But experience has shown that both could have
|
|
511
|
+
// sent a command at roughly the same time, using the same SPAN for encryption.
|
|
512
|
+
// To avoid a nasty desync and both nodes trying to resync at the same time, causing message loss,
|
|
513
|
+
// we accept commands encrypted with the previous SPAN under very specific circumstances:
|
|
514
|
+
if (
|
|
515
|
+
// The previous SPAN is still known, i.e. the node didn't send another command that was successfully decrypted
|
|
516
|
+
!!spanState.currentSPAN &&
|
|
517
|
+
// it is still valid
|
|
518
|
+
spanState.currentSPAN.expires > (0, core_1.highResTimestamp)() &&
|
|
519
|
+
// The received command is exactly the next, expected one
|
|
520
|
+
prevSequenceNumber != undefined &&
|
|
521
|
+
this._sequenceNumber ===
|
|
522
|
+
((prevSequenceNumber + 1) & 0xff) &&
|
|
523
|
+
// And in case of a mock-based test, do this only on the controller
|
|
524
|
+
!this.host.__internalIsMockNode) {
|
|
525
|
+
const nonce = spanState.currentSPAN.nonce;
|
|
526
|
+
spanState.currentSPAN = undefined;
|
|
527
|
+
return decryptWithNonce(nonce);
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
// forgetting the current SPAN shouldn't be necessary but better be safe than sorry
|
|
531
|
+
spanState.currentSPAN = undefined;
|
|
532
|
+
}
|
|
468
533
|
// This can only happen if the security class is known
|
|
469
534
|
return getNonceAndDecrypt();
|
|
470
535
|
}
|
|
@@ -476,18 +541,18 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
476
541
|
return failNoSPAN();
|
|
477
542
|
const receiverEI = spanState.receiverEI;
|
|
478
543
|
// How we do this depends on whether we know the security class of the other node
|
|
479
|
-
if (this.host.securityManager2.tempKeys.has(
|
|
544
|
+
if (this.host.securityManager2.tempKeys.has(sendingNodeId)) {
|
|
480
545
|
// We're currently bootstrapping the node, it might be using a temporary key
|
|
481
|
-
this.host.securityManager2.initializeTempSPAN(
|
|
546
|
+
this.host.securityManager2.initializeTempSPAN(sendingNodeId, senderEI, receiverEI);
|
|
482
547
|
const ret = getNonceAndDecrypt();
|
|
483
548
|
// Decryption with the temporary key worked
|
|
484
549
|
if (ret.authOK)
|
|
485
550
|
return ret;
|
|
486
551
|
// Reset the SPAN state and try with the recently granted security class
|
|
487
|
-
this.host.securityManager2.setSPANState(
|
|
552
|
+
this.host.securityManager2.setSPANState(sendingNodeId, spanState);
|
|
488
553
|
}
|
|
489
554
|
if (securityClass != undefined) {
|
|
490
|
-
this.host.securityManager2.initializeSPAN(
|
|
555
|
+
this.host.securityManager2.initializeSPAN(sendingNodeId, securityClass, senderEI, receiverEI);
|
|
491
556
|
return getNonceAndDecrypt();
|
|
492
557
|
}
|
|
493
558
|
else {
|
|
@@ -495,18 +560,18 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
495
560
|
// Try multiple security classes
|
|
496
561
|
const possibleSecurityClasses = core_1.securityClassOrder
|
|
497
562
|
.filter((s) => (0, core_1.securityClassIsS2)(s))
|
|
498
|
-
.filter((s) => this.host.hasSecurityClass(
|
|
563
|
+
.filter((s) => this.host.hasSecurityClass(sendingNodeId, s) !== false);
|
|
499
564
|
for (const secClass of possibleSecurityClasses) {
|
|
500
565
|
// Initialize an SPAN with that security class
|
|
501
|
-
this.host.securityManager2.initializeSPAN(
|
|
566
|
+
this.host.securityManager2.initializeSPAN(sendingNodeId, secClass, senderEI, receiverEI);
|
|
502
567
|
const ret = getNonceAndDecrypt();
|
|
503
568
|
// It worked, return the result and remember the security class
|
|
504
569
|
if (ret.authOK) {
|
|
505
|
-
this.host.setSecurityClass(
|
|
570
|
+
this.host.setSecurityClass(sendingNodeId, secClass, true);
|
|
506
571
|
return ret;
|
|
507
572
|
}
|
|
508
573
|
// Reset the SPAN state and try with the next security class
|
|
509
|
-
this.host.securityManager2.setSPANState(
|
|
574
|
+
this.host.securityManager2.setSPANState(sendingNodeId, spanState);
|
|
510
575
|
}
|
|
511
576
|
}
|
|
512
577
|
}
|
|
@@ -515,12 +580,13 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
515
580
|
};
|
|
516
581
|
let plaintext;
|
|
517
582
|
let authOK = false;
|
|
518
|
-
let
|
|
583
|
+
let key;
|
|
584
|
+
let iv;
|
|
519
585
|
// If the Receiver is unable to authenticate the singlecast message with the current SPAN,
|
|
520
586
|
// the Receiver SHOULD try decrypting the message with one or more of the following SPAN values,
|
|
521
587
|
// stopping when decryption is successful or the maximum number of iterations is reached.
|
|
522
588
|
for (let i = 0; i < DECRYPT_ATTEMPTS; i++) {
|
|
523
|
-
({ plaintext, authOK,
|
|
589
|
+
({ plaintext, authOK, key, iv } = decrypt());
|
|
524
590
|
if (!!authOK && !!plaintext)
|
|
525
591
|
break;
|
|
526
592
|
}
|
|
@@ -544,7 +610,8 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
544
610
|
encapCC: this,
|
|
545
611
|
});
|
|
546
612
|
}
|
|
547
|
-
this.
|
|
613
|
+
this.key = key;
|
|
614
|
+
this.iv = iv;
|
|
548
615
|
}
|
|
549
616
|
else {
|
|
550
617
|
this._securityClass = options.securityClass;
|
|
@@ -594,9 +661,9 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
594
661
|
}
|
|
595
662
|
serialize() {
|
|
596
663
|
// TODO: Support Multicast
|
|
597
|
-
const nodeId = this.nodeId;
|
|
598
664
|
// Include Sender EI in the command if we only have the receiver's EI
|
|
599
|
-
const
|
|
665
|
+
const receiverNodeId = this.getDestinationIDTX();
|
|
666
|
+
const spanState = this.host.securityManager2.getSPANState(receiverNodeId);
|
|
600
667
|
if (spanState.type === core_1.SPANState.None ||
|
|
601
668
|
spanState.type === core_1.SPANState.LocalEI) {
|
|
602
669
|
// Can't do anything here if we don't have the receiver's EI
|
|
@@ -609,16 +676,16 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
609
676
|
const receiverEI = spanState.receiverEI;
|
|
610
677
|
// While bootstrapping a node, the controller only sends commands encrypted
|
|
611
678
|
// with the temporary key
|
|
612
|
-
if (this.host.securityManager2.tempKeys.has(
|
|
613
|
-
this.host.securityManager2.initializeTempSPAN(
|
|
679
|
+
if (this.host.securityManager2.tempKeys.has(receiverNodeId)) {
|
|
680
|
+
this.host.securityManager2.initializeTempSPAN(receiverNodeId, senderEI, receiverEI);
|
|
614
681
|
}
|
|
615
682
|
else {
|
|
616
683
|
const securityClass = this._securityClass ??
|
|
617
|
-
this.host.getHighestSecurityClass(
|
|
684
|
+
this.host.getHighestSecurityClass(receiverNodeId);
|
|
618
685
|
if (securityClass == undefined) {
|
|
619
686
|
throw new core_1.ZWaveError("No security class defined for this command!", core_1.ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
620
687
|
}
|
|
621
|
-
this.host.securityManager2.initializeSPAN(
|
|
688
|
+
this.host.securityManager2.initializeSPAN(receiverNodeId, securityClass, senderEI, receiverEI);
|
|
622
689
|
}
|
|
623
690
|
// Add or update the SPAN extension
|
|
624
691
|
let spanExtension = this.extensions.find((e) => e instanceof Extension_1.SPANExtension);
|
|
@@ -647,14 +714,19 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
647
714
|
]);
|
|
648
715
|
// Generate the authentication data for CCM encryption
|
|
649
716
|
const messageLength = this.computeEncapsulationOverhead() + serializedCC.length;
|
|
650
|
-
const authData = getAuthenticationData(this.host.ownNodeId,
|
|
651
|
-
|
|
717
|
+
const authData = getAuthenticationData(this.host.ownNodeId, receiverNodeId, this.host.homeId, messageLength, unencryptedPayload);
|
|
718
|
+
// Generate a nonce for encryption, and remember it to attempt decryption
|
|
719
|
+
// of potential in-flight messages from the target node.
|
|
720
|
+
const iv = this.host.securityManager2.nextNonce(receiverNodeId, true);
|
|
652
721
|
const { keyCCM: key } =
|
|
653
722
|
// Prefer the overridden security class if it was given
|
|
654
723
|
this._securityClass != undefined
|
|
655
724
|
? this.host.securityManager2.getKeysForSecurityClass(this._securityClass)
|
|
656
|
-
: this.host.securityManager2.getKeysForNode(
|
|
725
|
+
: this.host.securityManager2.getKeysForNode(receiverNodeId);
|
|
657
726
|
const { ciphertext: ciphertextPayload, authTag } = (0, core_1.encryptAES128CCM)(key, iv, plaintextPayload, authData, core_1.SECURITY_S2_AUTH_TAG_LENGTH);
|
|
727
|
+
// Remember key and IV for debugging purposes
|
|
728
|
+
this.key = key;
|
|
729
|
+
this.iv = iv;
|
|
658
730
|
this.payload = Buffer.concat([
|
|
659
731
|
unencryptedPayload,
|
|
660
732
|
ciphertextPayload,
|
|
@@ -685,6 +757,15 @@ let Security2CCMessageEncapsulation = class Security2CCMessageEncapsulation exte
|
|
|
685
757
|
.map((e) => e.toLogEntry())
|
|
686
758
|
.join("");
|
|
687
759
|
}
|
|
760
|
+
// Log the used keys in integration tests
|
|
761
|
+
if (process.env.NODE_ENV === "test") {
|
|
762
|
+
if (this.key) {
|
|
763
|
+
message.key = (0, safe_2.buffer2hex)(this.key);
|
|
764
|
+
}
|
|
765
|
+
if (this.iv) {
|
|
766
|
+
message.IV = (0, safe_2.buffer2hex)(this.iv);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
688
769
|
return {
|
|
689
770
|
...super.toLogEntry(applHost),
|
|
690
771
|
message,
|
|
@@ -701,7 +782,7 @@ let Security2CCNonceReport = class Security2CCNonceReport extends Security2CC {
|
|
|
701
782
|
super(host, options);
|
|
702
783
|
// Make sure that we can send/receive secure commands
|
|
703
784
|
assertSecurity.call(this, options);
|
|
704
|
-
if ((0,
|
|
785
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
705
786
|
(0, core_1.validatePayload)(this.payload.length >= 2);
|
|
706
787
|
this._sequenceNumber = this.payload[0];
|
|
707
788
|
// Don't accept duplicate commands
|
|
@@ -755,7 +836,7 @@ let Security2CCNonceReport = class Security2CCNonceReport extends Security2CC {
|
|
|
755
836
|
MOS: this.MOS,
|
|
756
837
|
};
|
|
757
838
|
if (this.receiverEI) {
|
|
758
|
-
message["receiver entropy"] = (0,
|
|
839
|
+
message["receiver entropy"] = (0, safe_2.buffer2hex)(this.receiverEI);
|
|
759
840
|
}
|
|
760
841
|
return {
|
|
761
842
|
...super.toLogEntry(applHost),
|
|
@@ -772,7 +853,7 @@ let Security2CCNonceGet = class Security2CCNonceGet extends Security2CC {
|
|
|
772
853
|
super(host, options);
|
|
773
854
|
// Make sure that we can send/receive secure commands
|
|
774
855
|
assertSecurity.call(this, options);
|
|
775
|
-
if ((0,
|
|
856
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
776
857
|
(0, core_1.validatePayload)(this.payload.length >= 1);
|
|
777
858
|
this._sequenceNumber = this.payload[0];
|
|
778
859
|
// Don't accept duplicate commands
|
|
@@ -814,7 +895,7 @@ exports.Security2CCNonceGet = Security2CCNonceGet;
|
|
|
814
895
|
let Security2CCKEXReport = class Security2CCKEXReport extends Security2CC {
|
|
815
896
|
constructor(host, options) {
|
|
816
897
|
super(host, options);
|
|
817
|
-
if ((0,
|
|
898
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
818
899
|
(0, core_1.validatePayload)(this.payload.length >= 4);
|
|
819
900
|
this.requestCSA = !!(this.payload[0] & 0b10);
|
|
820
901
|
this.echo = !!(this.payload[0] & 0b1);
|
|
@@ -847,14 +928,14 @@ let Security2CCKEXReport = class Security2CCKEXReport extends Security2CC {
|
|
|
847
928
|
message: {
|
|
848
929
|
echo: this.echo,
|
|
849
930
|
"supported schemes": this.supportedKEXSchemes
|
|
850
|
-
.map((s) => `\n· ${(0,
|
|
931
|
+
.map((s) => `\n· ${(0, safe_2.getEnumMemberName)(shared_1.KEXSchemes, s)}`)
|
|
851
932
|
.join(""),
|
|
852
933
|
"supported ECDH profiles": this.supportedECDHProfiles
|
|
853
|
-
.map((s) => `\n· ${(0,
|
|
934
|
+
.map((s) => `\n· ${(0, safe_2.getEnumMemberName)(shared_1.ECDHProfiles, s)}`)
|
|
854
935
|
.join(""),
|
|
855
936
|
"CSA requested": this.requestCSA,
|
|
856
937
|
"requested security classes": this.requestedKeys
|
|
857
|
-
.map((s) => `\n· ${(0,
|
|
938
|
+
.map((s) => `\n· ${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, s)}`)
|
|
858
939
|
.join(""),
|
|
859
940
|
},
|
|
860
941
|
};
|
|
@@ -874,7 +955,7 @@ exports.Security2CCKEXGet = Security2CCKEXGet;
|
|
|
874
955
|
let Security2CCKEXSet = class Security2CCKEXSet extends Security2CC {
|
|
875
956
|
constructor(host, options) {
|
|
876
957
|
super(host, options);
|
|
877
|
-
if ((0,
|
|
958
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
878
959
|
(0, core_1.validatePayload)(this.payload.length >= 4);
|
|
879
960
|
this.permitCSA = !!(this.payload[0] & 0b10);
|
|
880
961
|
this.echo = !!(this.payload[0] & 0b1);
|
|
@@ -910,11 +991,11 @@ let Security2CCKEXSet = class Security2CCKEXSet extends Security2CC {
|
|
|
910
991
|
...super.toLogEntry(applHost),
|
|
911
992
|
message: {
|
|
912
993
|
echo: this.echo,
|
|
913
|
-
"selected scheme": (0,
|
|
914
|
-
"selected ECDH profile": (0,
|
|
994
|
+
"selected scheme": (0, safe_2.getEnumMemberName)(shared_1.KEXSchemes, this.selectedKEXScheme),
|
|
995
|
+
"selected ECDH profile": (0, safe_2.getEnumMemberName)(shared_1.ECDHProfiles, this.selectedECDHProfile),
|
|
915
996
|
"CSA permitted": this.permitCSA,
|
|
916
997
|
"granted security classes": this.grantedKeys
|
|
917
|
-
.map((s) => `\n· ${(0,
|
|
998
|
+
.map((s) => `\n· ${(0, safe_2.getEnumMemberName)(core_1.SecurityClass, s)}`)
|
|
918
999
|
.join(""),
|
|
919
1000
|
},
|
|
920
1001
|
};
|
|
@@ -927,7 +1008,7 @@ exports.Security2CCKEXSet = Security2CCKEXSet;
|
|
|
927
1008
|
let Security2CCKEXFail = class Security2CCKEXFail extends Security2CC {
|
|
928
1009
|
constructor(host, options) {
|
|
929
1010
|
super(host, options);
|
|
930
|
-
if ((0,
|
|
1011
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
931
1012
|
(0, core_1.validatePayload)(this.payload.length >= 1);
|
|
932
1013
|
this.failType = this.payload[0];
|
|
933
1014
|
}
|
|
@@ -942,7 +1023,7 @@ let Security2CCKEXFail = class Security2CCKEXFail extends Security2CC {
|
|
|
942
1023
|
toLogEntry(applHost) {
|
|
943
1024
|
return {
|
|
944
1025
|
...super.toLogEntry(applHost),
|
|
945
|
-
message: { reason: (0,
|
|
1026
|
+
message: { reason: (0, safe_2.getEnumMemberName)(shared_1.KEXFailType, this.failType) },
|
|
946
1027
|
};
|
|
947
1028
|
}
|
|
948
1029
|
};
|
|
@@ -953,7 +1034,7 @@ exports.Security2CCKEXFail = Security2CCKEXFail;
|
|
|
953
1034
|
let Security2CCPublicKeyReport = class Security2CCPublicKeyReport extends Security2CC {
|
|
954
1035
|
constructor(host, options) {
|
|
955
1036
|
super(host, options);
|
|
956
|
-
if ((0,
|
|
1037
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
957
1038
|
(0, core_1.validatePayload)(this.payload.length >= 17);
|
|
958
1039
|
this.includingNode = !!(this.payload[0] & 0b1);
|
|
959
1040
|
this.publicKey = this.payload.slice(1);
|
|
@@ -975,7 +1056,7 @@ let Security2CCPublicKeyReport = class Security2CCPublicKeyReport extends Securi
|
|
|
975
1056
|
...super.toLogEntry(applHost),
|
|
976
1057
|
message: {
|
|
977
1058
|
"is including node": this.includingNode,
|
|
978
|
-
"public key": (0,
|
|
1059
|
+
"public key": (0, safe_2.buffer2hex)(this.publicKey),
|
|
979
1060
|
},
|
|
980
1061
|
};
|
|
981
1062
|
}
|
|
@@ -987,7 +1068,7 @@ exports.Security2CCPublicKeyReport = Security2CCPublicKeyReport;
|
|
|
987
1068
|
let Security2CCNetworkKeyReport = class Security2CCNetworkKeyReport extends Security2CC {
|
|
988
1069
|
constructor(host, options) {
|
|
989
1070
|
super(host, options);
|
|
990
|
-
if ((0,
|
|
1071
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
991
1072
|
// TODO: Deserialize payload
|
|
992
1073
|
throw new core_1.ZWaveError(`${this.constructor.name}: deserialization not implemented`, core_1.ZWaveErrorCodes.Deserialization_NotImplemented);
|
|
993
1074
|
}
|
|
@@ -1007,7 +1088,7 @@ let Security2CCNetworkKeyReport = class Security2CCNetworkKeyReport extends Secu
|
|
|
1007
1088
|
return {
|
|
1008
1089
|
...super.toLogEntry(applHost),
|
|
1009
1090
|
message: {
|
|
1010
|
-
"security class": (0,
|
|
1091
|
+
"security class": (0, safe_2.getEnumMemberName)(core_1.SecurityClass, this.grantedKey),
|
|
1011
1092
|
// This shouldn't be logged, so users can safely post their logs online
|
|
1012
1093
|
// "network key": buffer2hex(this.networkKey),
|
|
1013
1094
|
},
|
|
@@ -1021,7 +1102,7 @@ exports.Security2CCNetworkKeyReport = Security2CCNetworkKeyReport;
|
|
|
1021
1102
|
let Security2CCNetworkKeyGet = class Security2CCNetworkKeyGet extends Security2CC {
|
|
1022
1103
|
constructor(host, options) {
|
|
1023
1104
|
super(host, options);
|
|
1024
|
-
if ((0,
|
|
1105
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
1025
1106
|
(0, core_1.validatePayload)(this.payload.length >= 1);
|
|
1026
1107
|
this.requestedKey = bitMaskToSecurityClass(this.payload, 0);
|
|
1027
1108
|
}
|
|
@@ -1037,7 +1118,7 @@ let Security2CCNetworkKeyGet = class Security2CCNetworkKeyGet extends Security2C
|
|
|
1037
1118
|
return {
|
|
1038
1119
|
...super.toLogEntry(applHost),
|
|
1039
1120
|
message: {
|
|
1040
|
-
"security class": (0,
|
|
1121
|
+
"security class": (0, safe_2.getEnumMemberName)(core_1.SecurityClass, this.requestedKey),
|
|
1041
1122
|
},
|
|
1042
1123
|
};
|
|
1043
1124
|
}
|
|
@@ -1056,7 +1137,7 @@ exports.Security2CCNetworkKeyVerify = Security2CCNetworkKeyVerify;
|
|
|
1056
1137
|
let Security2CCTransferEnd = class Security2CCTransferEnd extends Security2CC {
|
|
1057
1138
|
constructor(host, options) {
|
|
1058
1139
|
super(host, options);
|
|
1059
|
-
if ((0,
|
|
1140
|
+
if ((0, CommandClass_1.gotDeserializationOptions)(options)) {
|
|
1060
1141
|
(0, core_1.validatePayload)(this.payload.length >= 1);
|
|
1061
1142
|
this.keyVerified = !!(this.payload[0] & 0b10);
|
|
1062
1143
|
this.keyRequestComplete = !!(this.payload[0] & 0b1);
|