@zwave-js/cc 14.0.0-beta.4 → 14.0.0-beta.5
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 +381 -266
- package/build/cjs/cc/AlarmSensorCC.js.map +3 -3
- package/build/cjs/cc/AssociationCC.js +669 -503
- package/build/cjs/cc/AssociationCC.js.map +3 -3
- package/build/cjs/cc/AssociationGroupInfoCC.js +633 -492
- package/build/cjs/cc/AssociationGroupInfoCC.js.map +3 -3
- package/build/cjs/cc/BarrierOperatorCC.js +595 -429
- package/build/cjs/cc/BarrierOperatorCC.js.map +3 -3
- package/build/cjs/cc/BasicCC.js +354 -260
- package/build/cjs/cc/BasicCC.js.map +3 -3
- package/build/cjs/cc/BatteryCC.js +427 -345
- package/build/cjs/cc/BatteryCC.js.map +3 -3
- package/build/cjs/cc/BinarySensorCC.js +391 -276
- package/build/cjs/cc/BinarySensorCC.js.map +3 -3
- package/build/cjs/cc/BinarySwitchCC.js +347 -253
- package/build/cjs/cc/BinarySwitchCC.js.map +3 -3
- package/build/cjs/cc/CRC16CC.js +160 -85
- package/build/cjs/cc/CRC16CC.js.map +3 -3
- package/build/cjs/cc/CentralSceneCC.js +459 -324
- package/build/cjs/cc/CentralSceneCC.js.map +3 -3
- package/build/cjs/cc/ClimateControlScheduleCC.js +459 -293
- package/build/cjs/cc/ClimateControlScheduleCC.js.map +3 -3
- package/build/cjs/cc/ClockCC.js +254 -150
- package/build/cjs/cc/ClockCC.js.map +3 -3
- package/build/cjs/cc/ColorSwitchCC.js +758 -610
- package/build/cjs/cc/ColorSwitchCC.js.map +3 -3
- package/build/cjs/cc/ConfigurationCC.js +1700 -1453
- package/build/cjs/cc/ConfigurationCC.js.map +3 -3
- package/build/cjs/cc/DeviceResetLocallyCC.js +125 -49
- package/build/cjs/cc/DeviceResetLocallyCC.js.map +3 -3
- package/build/cjs/cc/DoorLockCC.js +904 -777
- package/build/cjs/cc/DoorLockCC.js.map +3 -3
- package/build/cjs/cc/DoorLockLoggingCC.js +321 -206
- package/build/cjs/cc/DoorLockLoggingCC.js.map +3 -3
- package/build/cjs/cc/EnergyProductionCC.js +249 -160
- package/build/cjs/cc/EnergyProductionCC.js.map +3 -3
- package/build/cjs/cc/EntryControlCC.js +619 -458
- package/build/cjs/cc/EntryControlCC.js.map +3 -3
- package/build/cjs/cc/FirmwareUpdateMetaDataCC.js +898 -698
- package/build/cjs/cc/FirmwareUpdateMetaDataCC.js.map +3 -3
- package/build/cjs/cc/HailCC.js +57 -11
- package/build/cjs/cc/HailCC.js.map +2 -2
- package/build/cjs/cc/HumidityControlModeCC.js +359 -233
- package/build/cjs/cc/HumidityControlModeCC.js.map +3 -3
- package/build/cjs/cc/HumidityControlOperatingStateCC.js +189 -103
- package/build/cjs/cc/HumidityControlOperatingStateCC.js.map +3 -3
- package/build/cjs/cc/HumidityControlSetpointCC.js +682 -495
- package/build/cjs/cc/HumidityControlSetpointCC.js.map +3 -3
- package/build/cjs/cc/InclusionControllerCC.js +205 -114
- package/build/cjs/cc/InclusionControllerCC.js.map +3 -3
- package/build/cjs/cc/IndicatorCC.js +897 -736
- package/build/cjs/cc/IndicatorCC.js.map +3 -3
- package/build/cjs/cc/IrrigationCC.js +1651 -1405
- package/build/cjs/cc/IrrigationCC.js.map +3 -3
- package/build/cjs/cc/LanguageCC.js +268 -171
- package/build/cjs/cc/LanguageCC.js.map +3 -3
- package/build/cjs/cc/LockCC.js +254 -154
- package/build/cjs/cc/LockCC.js.map +3 -3
- package/build/cjs/cc/ManufacturerProprietaryCC.js +189 -129
- package/build/cjs/cc/ManufacturerProprietaryCC.js.map +2 -2
- package/build/cjs/cc/ManufacturerSpecificCC.js +319 -213
- package/build/cjs/cc/ManufacturerSpecificCC.js.map +3 -3
- package/build/cjs/cc/MeterCC.js +827 -707
- package/build/cjs/cc/MeterCC.js.map +3 -3
- package/build/cjs/cc/MultiChannelAssociationCC.js +612 -478
- package/build/cjs/cc/MultiChannelAssociationCC.js.map +3 -3
- package/build/cjs/cc/MultiChannelCC.js +1037 -819
- package/build/cjs/cc/MultiChannelCC.js.map +3 -3
- package/build/cjs/cc/MultiCommandCC.js +172 -97
- package/build/cjs/cc/MultiCommandCC.js.map +3 -3
- package/build/cjs/cc/MultilevelSensorCC.js +589 -449
- package/build/cjs/cc/MultilevelSensorCC.js.map +3 -3
- package/build/cjs/cc/MultilevelSwitchCC.js +587 -439
- package/build/cjs/cc/MultilevelSwitchCC.js.map +3 -3
- package/build/cjs/cc/NoOperationCC.js +89 -27
- package/build/cjs/cc/NoOperationCC.js.map +2 -2
- package/build/cjs/cc/NodeNamingCC.js +417 -277
- package/build/cjs/cc/NodeNamingCC.js.map +3 -3
- package/build/cjs/cc/NotificationCC.js +972 -818
- package/build/cjs/cc/NotificationCC.js.map +3 -3
- package/build/cjs/cc/PowerlevelCC.js +450 -303
- package/build/cjs/cc/PowerlevelCC.js.map +3 -3
- package/build/cjs/cc/ProtectionCC.js +686 -494
- package/build/cjs/cc/ProtectionCC.js.map +3 -3
- package/build/cjs/cc/SceneActivationCC.js +165 -97
- package/build/cjs/cc/SceneActivationCC.js.map +3 -3
- package/build/cjs/cc/SceneActuatorConfigurationCC.js +346 -243
- package/build/cjs/cc/SceneActuatorConfigurationCC.js.map +3 -3
- package/build/cjs/cc/SceneControllerConfigurationCC.js +401 -298
- package/build/cjs/cc/SceneControllerConfigurationCC.js.map +3 -3
- package/build/cjs/cc/ScheduleEntryLockCC.js +1552 -1272
- package/build/cjs/cc/ScheduleEntryLockCC.js.map +3 -3
- package/build/cjs/cc/Security2CC.js +1483 -1219
- package/build/cjs/cc/Security2CC.js.map +3 -3
- package/build/cjs/cc/SecurityCC.js +839 -619
- package/build/cjs/cc/SecurityCC.js.map +3 -3
- package/build/cjs/cc/SoundSwitchCC.js +707 -515
- package/build/cjs/cc/SoundSwitchCC.js.map +3 -3
- package/build/cjs/cc/SupervisionCC.js +327 -237
- package/build/cjs/cc/SupervisionCC.js.map +3 -3
- package/build/cjs/cc/ThermostatFanModeCC.js +386 -263
- package/build/cjs/cc/ThermostatFanModeCC.js.map +3 -3
- package/build/cjs/cc/ThermostatFanStateCC.js +192 -106
- package/build/cjs/cc/ThermostatFanStateCC.js.map +3 -3
- package/build/cjs/cc/ThermostatModeCC.js +425 -302
- package/build/cjs/cc/ThermostatModeCC.js.map +3 -3
- package/build/cjs/cc/ThermostatOperatingStateCC.js +188 -102
- package/build/cjs/cc/ThermostatOperatingStateCC.js.map +3 -3
- package/build/cjs/cc/ThermostatSetbackCC.js +277 -173
- package/build/cjs/cc/ThermostatSetbackCC.js.map +3 -3
- package/build/cjs/cc/ThermostatSetpointCC.js +645 -491
- package/build/cjs/cc/ThermostatSetpointCC.js.map +3 -3
- package/build/cjs/cc/TimeCC.js +515 -353
- package/build/cjs/cc/TimeCC.js.map +3 -3
- package/build/cjs/cc/TimeParametersCC.js +302 -202
- package/build/cjs/cc/TimeParametersCC.js.map +3 -3
- package/build/cjs/cc/TransportServiceCC.js +433 -315
- package/build/cjs/cc/TransportServiceCC.js.map +3 -3
- package/build/cjs/cc/UserCodeCC.js +1385 -1102
- package/build/cjs/cc/UserCodeCC.js.map +3 -3
- package/build/cjs/cc/VersionCC.js +696 -562
- package/build/cjs/cc/VersionCC.js.map +3 -3
- package/build/cjs/cc/WakeUpCC.js +499 -346
- package/build/cjs/cc/WakeUpCC.js.map +3 -3
- package/build/cjs/cc/WindowCoveringCC.js +626 -478
- package/build/cjs/cc/WindowCoveringCC.js.map +3 -3
- package/build/cjs/cc/ZWaveLongRangeCC.js +57 -10
- package/build/cjs/cc/ZWaveLongRangeCC.js.map +2 -2
- package/build/cjs/cc/ZWavePlusCC.js +233 -159
- package/build/cjs/cc/ZWavePlusCC.js.map +3 -3
- package/build/cjs/cc/ZWaveProtocolCC.js +1515 -948
- package/build/cjs/cc/ZWaveProtocolCC.js.map +3 -3
- package/build/cjs/cc/manufacturerProprietary/Decorators.d.ts +4 -4
- package/build/cjs/cc/manufacturerProprietary/Decorators.js.map +1 -1
- package/build/cjs/cc/manufacturerProprietary/FibaroCC.js +395 -274
- package/build/cjs/cc/manufacturerProprietary/FibaroCC.js.map +3 -3
- package/build/cjs/lib/CommandClassDecorators.d.ts +11 -15
- package/build/cjs/lib/CommandClassDecorators.js +19 -20
- package/build/cjs/lib/CommandClassDecorators.js.map +2 -2
- package/build/cjs/lib/Security2/Extension.d.ts +1 -1
- package/build/cjs/lib/Security2/Extension.js +217 -126
- package/build/cjs/lib/Security2/Extension.js.map +3 -3
- package/build/esm/cc/AlarmSensorCC.d.ts.map +1 -1
- package/build/esm/cc/AlarmSensorCC.js +389 -291
- package/build/esm/cc/AlarmSensorCC.js.map +1 -1
- package/build/esm/cc/AssociationCC.d.ts.map +1 -1
- package/build/esm/cc/AssociationCC.js +678 -537
- package/build/esm/cc/AssociationCC.js.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.d.ts.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.js +659 -539
- package/build/esm/cc/AssociationGroupInfoCC.js.map +1 -1
- package/build/esm/cc/BarrierOperatorCC.d.ts.map +1 -1
- package/build/esm/cc/BarrierOperatorCC.js +634 -493
- package/build/esm/cc/BarrierOperatorCC.js.map +1 -1
- package/build/esm/cc/BasicCC.d.ts.map +1 -1
- package/build/esm/cc/BasicCC.js +380 -302
- package/build/esm/cc/BasicCC.js.map +1 -1
- package/build/esm/cc/BatteryCC.d.ts.map +1 -1
- package/build/esm/cc/BatteryCC.js +449 -384
- package/build/esm/cc/BatteryCC.js.map +1 -1
- package/build/esm/cc/BinarySensorCC.d.ts.map +1 -1
- package/build/esm/cc/BinarySensorCC.js +395 -297
- package/build/esm/cc/BinarySensorCC.js.map +1 -1
- package/build/esm/cc/BinarySwitchCC.d.ts.map +1 -1
- package/build/esm/cc/BinarySwitchCC.js +353 -274
- package/build/esm/cc/BinarySwitchCC.js.map +1 -1
- package/build/esm/cc/CRC16CC.js +162 -98
- package/build/esm/cc/CRC16CC.js.map +1 -1
- package/build/esm/cc/CentralSceneCC.d.ts.map +1 -1
- package/build/esm/cc/CentralSceneCC.js +465 -351
- package/build/esm/cc/CentralSceneCC.js.map +1 -1
- package/build/esm/cc/ClimateControlScheduleCC.d.ts.map +1 -1
- package/build/esm/cc/ClimateControlScheduleCC.js +454 -313
- package/build/esm/cc/ClimateControlScheduleCC.js.map +1 -1
- package/build/esm/cc/ClockCC.js +248 -159
- package/build/esm/cc/ClockCC.js.map +1 -1
- package/build/esm/cc/ColorSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/ColorSwitchCC.js +802 -677
- package/build/esm/cc/ColorSwitchCC.js.map +1 -1
- package/build/esm/cc/ConfigurationCC.js +1899 -1687
- package/build/esm/cc/ConfigurationCC.js.map +1 -1
- package/build/esm/cc/DeviceResetLocallyCC.js +124 -59
- package/build/esm/cc/DeviceResetLocallyCC.js.map +1 -1
- package/build/esm/cc/DoorLockCC.d.ts.map +1 -1
- package/build/esm/cc/DoorLockCC.js +951 -849
- package/build/esm/cc/DoorLockCC.js.map +1 -1
- package/build/esm/cc/DoorLockLoggingCC.d.ts.map +1 -1
- package/build/esm/cc/DoorLockLoggingCC.js +316 -218
- package/build/esm/cc/DoorLockLoggingCC.js.map +1 -1
- package/build/esm/cc/EnergyProductionCC.js +240 -164
- package/build/esm/cc/EnergyProductionCC.js.map +1 -1
- package/build/esm/cc/EntryControlCC.d.ts.map +1 -1
- package/build/esm/cc/EntryControlCC.js +629 -493
- package/build/esm/cc/EntryControlCC.js.map +1 -1
- package/build/esm/cc/FirmwareUpdateMetaDataCC.d.ts.map +1 -1
- package/build/esm/cc/FirmwareUpdateMetaDataCC.js +938 -769
- package/build/esm/cc/FirmwareUpdateMetaDataCC.js.map +1 -1
- package/build/esm/cc/HailCC.js +51 -12
- package/build/esm/cc/HailCC.js.map +1 -1
- package/build/esm/cc/HumidityControlModeCC.d.ts.map +1 -1
- package/build/esm/cc/HumidityControlModeCC.js +357 -250
- package/build/esm/cc/HumidityControlModeCC.js.map +1 -1
- package/build/esm/cc/HumidityControlOperatingStateCC.d.ts.map +1 -1
- package/build/esm/cc/HumidityControlOperatingStateCC.js +182 -109
- package/build/esm/cc/HumidityControlOperatingStateCC.js.map +1 -1
- package/build/esm/cc/HumidityControlSetpointCC.d.ts.map +1 -1
- package/build/esm/cc/HumidityControlSetpointCC.js +706 -546
- package/build/esm/cc/HumidityControlSetpointCC.js.map +1 -1
- package/build/esm/cc/InclusionControllerCC.js +197 -119
- package/build/esm/cc/InclusionControllerCC.js.map +1 -1
- package/build/esm/cc/IndicatorCC.js +973 -835
- package/build/esm/cc/IndicatorCC.js.map +1 -1
- package/build/esm/cc/IrrigationCC.d.ts.map +1 -1
- package/build/esm/cc/IrrigationCC.js +1697 -1496
- 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 +266 -184
- package/build/esm/cc/LanguageCC.js.map +1 -1
- package/build/esm/cc/LockCC.d.ts.map +1 -1
- package/build/esm/cc/LockCC.js +247 -162
- package/build/esm/cc/LockCC.js.map +1 -1
- package/build/esm/cc/ManufacturerProprietaryCC.js +192 -141
- package/build/esm/cc/ManufacturerProprietaryCC.js.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.d.ts.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.js +312 -223
- 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 +896 -795
- package/build/esm/cc/MeterCC.js.map +1 -1
- package/build/esm/cc/MultiChannelAssociationCC.d.ts.map +1 -1
- package/build/esm/cc/MultiChannelAssociationCC.js +631 -518
- package/build/esm/cc/MultiChannelAssociationCC.js.map +1 -1
- package/build/esm/cc/MultiChannelCC.d.ts.map +1 -1
- package/build/esm/cc/MultiChannelCC.js +1106 -921
- package/build/esm/cc/MultiChannelCC.js.map +1 -1
- package/build/esm/cc/MultiCommandCC.js +166 -102
- package/build/esm/cc/MultiCommandCC.js.map +1 -1
- package/build/esm/cc/MultilevelSensorCC.d.ts.map +1 -1
- package/build/esm/cc/MultilevelSensorCC.js +616 -497
- package/build/esm/cc/MultilevelSensorCC.js.map +1 -1
- package/build/esm/cc/MultilevelSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/MultilevelSwitchCC.js +621 -496
- package/build/esm/cc/MultilevelSwitchCC.js.map +1 -1
- package/build/esm/cc/NoOperationCC.js +82 -29
- package/build/esm/cc/NoOperationCC.js.map +1 -1
- package/build/esm/cc/NodeNamingCC.d.ts.map +1 -1
- package/build/esm/cc/NodeNamingCC.js +413 -294
- 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 +1097 -966
- package/build/esm/cc/NotificationCC.js.map +1 -1
- package/build/esm/cc/PowerlevelCC.js +437 -311
- package/build/esm/cc/PowerlevelCC.js.map +1 -1
- package/build/esm/cc/ProtectionCC.d.ts.map +1 -1
- package/build/esm/cc/ProtectionCC.js +704 -543
- package/build/esm/cc/ProtectionCC.js.map +1 -1
- package/build/esm/cc/SceneActivationCC.d.ts.map +1 -1
- package/build/esm/cc/SceneActivationCC.js +157 -100
- package/build/esm/cc/SceneActivationCC.js.map +1 -1
- package/build/esm/cc/SceneActuatorConfigurationCC.js +357 -269
- package/build/esm/cc/SceneActuatorConfigurationCC.js.map +1 -1
- package/build/esm/cc/SceneControllerConfigurationCC.js +434 -346
- package/build/esm/cc/SceneControllerConfigurationCC.js.map +1 -1
- package/build/esm/cc/ScheduleEntryLockCC.d.ts.map +1 -1
- package/build/esm/cc/ScheduleEntryLockCC.js +1596 -1357
- package/build/esm/cc/ScheduleEntryLockCC.js.map +1 -1
- package/build/esm/cc/Security2CC.js +1633 -1406
- package/build/esm/cc/Security2CC.js.map +1 -1
- package/build/esm/cc/SecurityCC.js +876 -687
- 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 +689 -526
- package/build/esm/cc/SoundSwitchCC.js.map +1 -1
- package/build/esm/cc/SupervisionCC.js +349 -272
- package/build/esm/cc/SupervisionCC.js.map +1 -1
- package/build/esm/cc/ThermostatFanModeCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatFanModeCC.js +388 -284
- package/build/esm/cc/ThermostatFanModeCC.js.map +1 -1
- package/build/esm/cc/ThermostatFanStateCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatFanStateCC.js +184 -111
- package/build/esm/cc/ThermostatFanStateCC.js.map +1 -1
- package/build/esm/cc/ThermostatModeCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatModeCC.js +435 -331
- package/build/esm/cc/ThermostatModeCC.js.map +1 -1
- package/build/esm/cc/ThermostatOperatingStateCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatOperatingStateCC.js +180 -107
- package/build/esm/cc/ThermostatOperatingStateCC.js.map +1 -1
- package/build/esm/cc/ThermostatSetbackCC.js +274 -185
- package/build/esm/cc/ThermostatSetbackCC.js.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.js +674 -543
- package/build/esm/cc/ThermostatSetpointCC.js.map +1 -1
- package/build/esm/cc/TimeCC.js +499 -360
- package/build/esm/cc/TimeCC.js.map +1 -1
- package/build/esm/cc/TimeParametersCC.d.ts.map +1 -1
- package/build/esm/cc/TimeParametersCC.js +296 -211
- package/build/esm/cc/TimeParametersCC.js.map +1 -1
- package/build/esm/cc/TransportServiceCC.js +464 -363
- package/build/esm/cc/TransportServiceCC.js.map +1 -1
- package/build/esm/cc/UserCodeCC.d.ts.map +1 -1
- package/build/esm/cc/UserCodeCC.js +1443 -1205
- package/build/esm/cc/UserCodeCC.js.map +1 -1
- package/build/esm/cc/VersionCC.d.ts.map +1 -1
- package/build/esm/cc/VersionCC.js +744 -635
- package/build/esm/cc/VersionCC.js.map +1 -1
- package/build/esm/cc/WakeUpCC.d.ts.map +1 -1
- package/build/esm/cc/WakeUpCC.js +494 -364
- package/build/esm/cc/WakeUpCC.js.map +1 -1
- package/build/esm/cc/WindowCoveringCC.d.ts.map +1 -1
- package/build/esm/cc/WindowCoveringCC.js +655 -530
- package/build/esm/cc/WindowCoveringCC.js.map +1 -1
- package/build/esm/cc/ZWaveLongRangeCC.js +51 -11
- package/build/esm/cc/ZWaveLongRangeCC.js.map +1 -1
- package/build/esm/cc/ZWavePlusCC.d.ts.map +1 -1
- package/build/esm/cc/ZWavePlusCC.js +223 -162
- package/build/esm/cc/ZWavePlusCC.js.map +1 -1
- package/build/esm/cc/ZWaveProtocolCC.js +1443 -953
- package/build/esm/cc/ZWaveProtocolCC.js.map +1 -1
- package/build/esm/cc/manufacturerProprietary/Decorators.d.ts +4 -4
- package/build/esm/cc/manufacturerProprietary/Decorators.d.ts.map +1 -1
- package/build/esm/cc/manufacturerProprietary/FibaroCC.js +390 -286
- package/build/esm/cc/manufacturerProprietary/FibaroCC.js.map +1 -1
- package/build/esm/lib/CommandClassDecorators.d.ts +11 -15
- package/build/esm/lib/CommandClassDecorators.d.ts.map +1 -1
- package/build/esm/lib/CommandClassDecorators.js +24 -24
- package/build/esm/lib/CommandClassDecorators.js.map +1 -1
- package/build/esm/lib/Security2/Extension.d.ts +1 -1
- package/build/esm/lib/Security2/Extension.d.ts.map +1 -1
- package/build/esm/lib/Security2/Extension.js +207 -123
- package/build/esm/lib/Security2/Extension.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
6
34
|
};
|
|
7
|
-
var Security2CC_1, Security2CCMessageEncapsulation_1, Security2CCNonceReport_1, Security2CCNonceGet_1, Security2CCKEXReport_1, Security2CCKEXSet_1, Security2CCKEXFail_1, Security2CCPublicKeyReport_1, Security2CCNetworkKeyReport_1, Security2CCNetworkKeyGet_1, Security2CCTransferEnd_1, Security2CCCommandsSupportedReport_1;
|
|
8
35
|
import { CommandClasses, MPANState, MessagePriority, SECURITY_S2_AUTH_TAG_LENGTH, SPANState, SecurityClass, TransmitOptions, ZWaveError, ZWaveErrorCodes, decryptAES128CCM, encodeBitMask, encryptAES128CCM, getCCName, highResTimestamp, isLongRangeNodeId, isTransmissionError, isZWaveError, parseBitMask, parseCCList, securityClassIsS2, securityClassOrder, validatePayload, } from "@zwave-js/core";
|
|
9
36
|
import { EncapsulationFlags, NODE_ID_BROADCAST, NODE_ID_BROADCAST_LR, encodeCCList, } from "@zwave-js/core/safe";
|
|
10
37
|
import { Bytes } from "@zwave-js/shared/safe";
|
|
@@ -245,563 +272,588 @@ function getSenderEI(extensions) {
|
|
|
245
272
|
// Encapsulation CCs are used internally and too frequently that we
|
|
246
273
|
// want to pay the cost of validating each call
|
|
247
274
|
/* eslint-disable @zwave-js/ccapi-validate-args */
|
|
248
|
-
let Security2CCAPI =
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
throw new ZWaveError(`Nonces can only be sent if secure communication is set up!`, ZWaveErrorCodes.Driver_NoSecurity);
|
|
263
|
-
}
|
|
264
|
-
const receiverEI = securityManager.generateNonce(this.endpoint.nodeId);
|
|
265
|
-
const cc = new Security2CCNonceReport({
|
|
266
|
-
nodeId: this.endpoint.nodeId,
|
|
267
|
-
endpointIndex: this.endpoint.index,
|
|
268
|
-
SOS: true,
|
|
269
|
-
MOS: false,
|
|
270
|
-
receiverEI,
|
|
271
|
-
});
|
|
272
|
-
try {
|
|
273
|
-
await this.host.sendCommand(cc, {
|
|
274
|
-
...this.commandOptions,
|
|
275
|
-
// Seems we need these options or some nodes won't accept the nonce
|
|
276
|
-
transmitOptions: TransmitOptions.ACK
|
|
277
|
-
| TransmitOptions.AutoRoute,
|
|
278
|
-
// Only try sending a nonce once
|
|
279
|
-
maxSendAttempts: 1,
|
|
280
|
-
// Nonce requests must be handled immediately
|
|
281
|
-
priority: MessagePriority.Immediate,
|
|
282
|
-
// We don't want failures causing us to treat the node as asleep or dead
|
|
283
|
-
changeNodeStatusOnMissingACK: false,
|
|
284
|
-
// And we need to react to
|
|
285
|
-
});
|
|
275
|
+
let Security2CCAPI = (() => {
|
|
276
|
+
let _classDecorators = [API(CommandClasses["Security 2"])];
|
|
277
|
+
let _classDescriptor;
|
|
278
|
+
let _classExtraInitializers = [];
|
|
279
|
+
let _classThis;
|
|
280
|
+
let _classSuper = CCAPI;
|
|
281
|
+
var Security2CCAPI = class extends _classSuper {
|
|
282
|
+
static { _classThis = this; }
|
|
283
|
+
static {
|
|
284
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
285
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
286
|
+
Security2CCAPI = _classThis = _classDescriptor.value;
|
|
287
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
288
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
286
289
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
290
|
+
supportsCommand(_cmd) {
|
|
291
|
+
// All commands are mandatory
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Sends a nonce to the node, either in response to a NonceGet request or a message that failed to decrypt. The message is sent without any retransmission etc.
|
|
296
|
+
* The return value indicates whether a nonce was successfully sent
|
|
297
|
+
*/
|
|
298
|
+
async sendNonce() {
|
|
299
|
+
this.assertSupportsCommand(Security2Command, Security2Command.NonceReport);
|
|
300
|
+
this.assertPhysicalEndpoint(this.endpoint);
|
|
301
|
+
const securityManager = getSecurityManager(this.host.ownNodeId, this.host, this.endpoint.nodeId);
|
|
302
|
+
if (!securityManager) {
|
|
303
|
+
throw new ZWaveError(`Nonces can only be sent if secure communication is set up!`, ZWaveErrorCodes.Driver_NoSecurity);
|
|
292
304
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
305
|
+
const receiverEI = securityManager.generateNonce(this.endpoint.nodeId);
|
|
306
|
+
const cc = new Security2CCNonceReport({
|
|
307
|
+
nodeId: this.endpoint.nodeId,
|
|
308
|
+
endpointIndex: this.endpoint.index,
|
|
309
|
+
SOS: true,
|
|
310
|
+
MOS: false,
|
|
311
|
+
receiverEI,
|
|
312
|
+
});
|
|
313
|
+
try {
|
|
314
|
+
await this.host.sendCommand(cc, {
|
|
315
|
+
...this.commandOptions,
|
|
316
|
+
// Seems we need these options or some nodes won't accept the nonce
|
|
317
|
+
transmitOptions: TransmitOptions.ACK
|
|
318
|
+
| TransmitOptions.AutoRoute,
|
|
319
|
+
// Only try sending a nonce once
|
|
320
|
+
maxSendAttempts: 1,
|
|
321
|
+
// Nonce requests must be handled immediately
|
|
322
|
+
priority: MessagePriority.Immediate,
|
|
323
|
+
// We don't want failures causing us to treat the node as asleep or dead
|
|
324
|
+
changeNodeStatusOnMissingACK: false,
|
|
325
|
+
// And we need to react to
|
|
326
|
+
});
|
|
296
327
|
}
|
|
328
|
+
catch (e) {
|
|
329
|
+
if (isTransmissionError(e)) {
|
|
330
|
+
// The nonce could not be sent, invalidate it
|
|
331
|
+
securityManager.deleteNonce(this.endpoint.nodeId);
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Pass other errors through
|
|
336
|
+
throw e;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return true;
|
|
297
340
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
SOS: false,
|
|
308
|
-
MOS: true,
|
|
309
|
-
});
|
|
310
|
-
try {
|
|
311
|
-
await this.host.sendCommand(cc, {
|
|
312
|
-
...this.commandOptions,
|
|
313
|
-
// Seems we need these options or some nodes won't accept the nonce
|
|
314
|
-
transmitOptions: TransmitOptions.ACK
|
|
315
|
-
| TransmitOptions.AutoRoute,
|
|
316
|
-
// Only try sending a nonce once
|
|
317
|
-
maxSendAttempts: 1,
|
|
318
|
-
// Nonce requests must be handled immediately
|
|
319
|
-
priority: MessagePriority.Immediate,
|
|
320
|
-
// We don't want failures causing us to treat the node as asleep or dead
|
|
321
|
-
changeNodeStatusOnMissingACK: false,
|
|
341
|
+
/** Notifies the target node that the MPAN state is out of sync */
|
|
342
|
+
async sendMOS() {
|
|
343
|
+
this.assertSupportsCommand(Security2Command, Security2Command.NonceReport);
|
|
344
|
+
this.assertPhysicalEndpoint(this.endpoint);
|
|
345
|
+
const cc = new Security2CCNonceReport({
|
|
346
|
+
nodeId: this.endpoint.nodeId,
|
|
347
|
+
endpointIndex: this.endpoint.index,
|
|
348
|
+
SOS: false,
|
|
349
|
+
MOS: true,
|
|
322
350
|
});
|
|
351
|
+
try {
|
|
352
|
+
await this.host.sendCommand(cc, {
|
|
353
|
+
...this.commandOptions,
|
|
354
|
+
// Seems we need these options or some nodes won't accept the nonce
|
|
355
|
+
transmitOptions: TransmitOptions.ACK
|
|
356
|
+
| TransmitOptions.AutoRoute,
|
|
357
|
+
// Only try sending a nonce once
|
|
358
|
+
maxSendAttempts: 1,
|
|
359
|
+
// Nonce requests must be handled immediately
|
|
360
|
+
priority: MessagePriority.Immediate,
|
|
361
|
+
// We don't want failures causing us to treat the node as asleep or dead
|
|
362
|
+
changeNodeStatusOnMissingACK: false,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
catch (e) {
|
|
366
|
+
if (isTransmissionError(e)) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// Pass other errors through
|
|
371
|
+
throw e;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return true;
|
|
323
375
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
376
|
+
/** Sends the given MPAN to the node */
|
|
377
|
+
async sendMPAN(groupId, innerMPANState) {
|
|
378
|
+
this.assertSupportsCommand(Security2Command, Security2Command.MessageEncapsulation);
|
|
379
|
+
this.assertPhysicalEndpoint(this.endpoint);
|
|
380
|
+
const cc = new Security2CCMessageEncapsulation({
|
|
381
|
+
nodeId: this.endpoint.nodeId,
|
|
382
|
+
endpointIndex: this.endpoint.index,
|
|
383
|
+
extensions: [
|
|
384
|
+
new MPANExtension({
|
|
385
|
+
groupId,
|
|
386
|
+
innerMPANState,
|
|
387
|
+
}),
|
|
388
|
+
],
|
|
389
|
+
});
|
|
390
|
+
try {
|
|
391
|
+
await this.host.sendCommand(cc, {
|
|
392
|
+
...this.commandOptions,
|
|
393
|
+
// Seems we need these options or some nodes won't accept the nonce
|
|
394
|
+
transmitOptions: TransmitOptions.ACK
|
|
395
|
+
| TransmitOptions.AutoRoute,
|
|
396
|
+
// Only try sending a nonce once
|
|
397
|
+
maxSendAttempts: 1,
|
|
398
|
+
// Nonce requests must be handled immediately
|
|
399
|
+
priority: MessagePriority.Immediate,
|
|
400
|
+
// We don't want failures causing us to treat the node as asleep or dead
|
|
401
|
+
changeNodeStatusOnMissingACK: false,
|
|
402
|
+
});
|
|
327
403
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
404
|
+
catch (e) {
|
|
405
|
+
if (isTransmissionError(e)) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// Pass other errors through
|
|
410
|
+
throw e;
|
|
411
|
+
}
|
|
331
412
|
}
|
|
413
|
+
return true;
|
|
332
414
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
415
|
+
/**
|
|
416
|
+
* Queries the securely supported commands for the current security class
|
|
417
|
+
* @param securityClass Can be used to overwrite the security class to use. If this doesn't match the current one, new nonces will need to be exchanged.
|
|
418
|
+
*/
|
|
419
|
+
async getSupportedCommands(securityClass) {
|
|
420
|
+
this.assertSupportsCommand(Security2Command, Security2Command.CommandsSupportedGet);
|
|
421
|
+
let cc = new Security2CCCommandsSupportedGet({
|
|
422
|
+
nodeId: this.endpoint.nodeId,
|
|
423
|
+
endpointIndex: this.endpoint.index,
|
|
424
|
+
});
|
|
425
|
+
// Security2CCCommandsSupportedGet is special because we cannot reply on the applHost to do the automatic
|
|
426
|
+
// encapsulation because it would use a different security class. Therefore the entire possible stack
|
|
427
|
+
// of encapsulation needs to be done here
|
|
428
|
+
if (MultiChannelCC.requiresEncapsulation(cc)) {
|
|
429
|
+
const multiChannelCCVersion = this.host.getSupportedCCVersion(CommandClasses["Multi Channel"], this.endpoint.nodeId);
|
|
430
|
+
cc = multiChannelCCVersion === 1
|
|
431
|
+
? MultiChannelCC.encapsulateV1(cc)
|
|
432
|
+
: MultiChannelCC.encapsulate(cc);
|
|
433
|
+
}
|
|
434
|
+
cc = Security2CC.encapsulate(cc, this.host.ownNodeId, this.host, { securityClass });
|
|
435
|
+
const response = await this.host.sendCommand(cc, {
|
|
351
436
|
...this.commandOptions,
|
|
352
|
-
|
|
353
|
-
transmitOptions: TransmitOptions.ACK
|
|
354
|
-
| TransmitOptions.AutoRoute,
|
|
355
|
-
// Only try sending a nonce once
|
|
356
|
-
maxSendAttempts: 1,
|
|
357
|
-
// Nonce requests must be handled immediately
|
|
358
|
-
priority: MessagePriority.Immediate,
|
|
359
|
-
// We don't want failures causing us to treat the node as asleep or dead
|
|
360
|
-
changeNodeStatusOnMissingACK: false,
|
|
437
|
+
autoEncapsulate: false,
|
|
361
438
|
});
|
|
439
|
+
return response?.supportedCCs;
|
|
362
440
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
441
|
+
async reportSupportedCommands(supportedCCs) {
|
|
442
|
+
this.assertSupportsCommand(Security2Command, Security2Command.CommandsSupportedReport);
|
|
443
|
+
const cc = new Security2CCCommandsSupportedReport({
|
|
444
|
+
nodeId: this.endpoint.nodeId,
|
|
445
|
+
endpointIndex: this.endpoint.index,
|
|
446
|
+
supportedCCs,
|
|
447
|
+
});
|
|
448
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
449
|
+
}
|
|
450
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
451
|
+
async getKeyExchangeParameters() {
|
|
452
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXGet);
|
|
453
|
+
const cc = new Security2CCKEXGet({
|
|
454
|
+
nodeId: this.endpoint.nodeId,
|
|
455
|
+
endpointIndex: this.endpoint.index,
|
|
456
|
+
});
|
|
457
|
+
const response = await this.host.sendCommand(cc, this.commandOptions);
|
|
458
|
+
if (response) {
|
|
459
|
+
return pick(response, [
|
|
460
|
+
"requestCSA",
|
|
461
|
+
"echo",
|
|
462
|
+
"supportedKEXSchemes",
|
|
463
|
+
"supportedECDHProfiles",
|
|
464
|
+
"requestedKeys",
|
|
465
|
+
"_reserved",
|
|
466
|
+
]);
|
|
370
467
|
}
|
|
371
468
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
endpointIndex: this.endpoint.index,
|
|
383
|
-
});
|
|
384
|
-
// Security2CCCommandsSupportedGet is special because we cannot reply on the applHost to do the automatic
|
|
385
|
-
// encapsulation because it would use a different security class. Therefore the entire possible stack
|
|
386
|
-
// of encapsulation needs to be done here
|
|
387
|
-
if (MultiChannelCC.requiresEncapsulation(cc)) {
|
|
388
|
-
const multiChannelCCVersion = this.host.getSupportedCCVersion(CommandClasses["Multi Channel"], this.endpoint.nodeId);
|
|
389
|
-
cc = multiChannelCCVersion === 1
|
|
390
|
-
? MultiChannelCC.encapsulateV1(cc)
|
|
391
|
-
: MultiChannelCC.encapsulate(cc);
|
|
392
|
-
}
|
|
393
|
-
cc = Security2CC.encapsulate(cc, this.host.ownNodeId, this.host, { securityClass });
|
|
394
|
-
const response = await this.host.sendCommand(cc, {
|
|
395
|
-
...this.commandOptions,
|
|
396
|
-
autoEncapsulate: false,
|
|
397
|
-
});
|
|
398
|
-
return response?.supportedCCs;
|
|
399
|
-
}
|
|
400
|
-
async reportSupportedCommands(supportedCCs) {
|
|
401
|
-
this.assertSupportsCommand(Security2Command, Security2Command.CommandsSupportedReport);
|
|
402
|
-
const cc = new Security2CCCommandsSupportedReport({
|
|
403
|
-
nodeId: this.endpoint.nodeId,
|
|
404
|
-
endpointIndex: this.endpoint.index,
|
|
405
|
-
supportedCCs,
|
|
406
|
-
});
|
|
407
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
408
|
-
}
|
|
409
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
410
|
-
async getKeyExchangeParameters() {
|
|
411
|
-
this.assertSupportsCommand(Security2Command, Security2Command.KEXGet);
|
|
412
|
-
const cc = new Security2CCKEXGet({
|
|
413
|
-
nodeId: this.endpoint.nodeId,
|
|
414
|
-
endpointIndex: this.endpoint.index,
|
|
415
|
-
});
|
|
416
|
-
const response = await this.host.sendCommand(cc, this.commandOptions);
|
|
417
|
-
if (response) {
|
|
418
|
-
return pick(response, [
|
|
419
|
-
"requestCSA",
|
|
420
|
-
"echo",
|
|
421
|
-
"supportedKEXSchemes",
|
|
422
|
-
"supportedECDHProfiles",
|
|
423
|
-
"requestedKeys",
|
|
424
|
-
"_reserved",
|
|
425
|
-
]);
|
|
469
|
+
/** Requests the given keys from an including node */
|
|
470
|
+
async requestKeys(params) {
|
|
471
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXReport);
|
|
472
|
+
const cc = new Security2CCKEXReport({
|
|
473
|
+
nodeId: this.endpoint.nodeId,
|
|
474
|
+
endpointIndex: this.endpoint.index,
|
|
475
|
+
...params,
|
|
476
|
+
echo: false,
|
|
477
|
+
});
|
|
478
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
426
479
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
438
|
-
}
|
|
439
|
-
/** Grants the joining node the given keys */
|
|
440
|
-
async grantKeys(params) {
|
|
441
|
-
this.assertSupportsCommand(Security2Command, Security2Command.KEXSet);
|
|
442
|
-
const cc = new Security2CCKEXSet({
|
|
443
|
-
nodeId: this.endpoint.nodeId,
|
|
444
|
-
endpointIndex: this.endpoint.index,
|
|
445
|
-
...params,
|
|
446
|
-
echo: false,
|
|
447
|
-
});
|
|
448
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
449
|
-
}
|
|
450
|
-
/** Confirms the keys that were requested by a node */
|
|
451
|
-
async confirmRequestedKeys(params) {
|
|
452
|
-
this.assertSupportsCommand(Security2Command, Security2Command.KEXReport);
|
|
453
|
-
const cc = new Security2CCKEXReport({
|
|
454
|
-
nodeId: this.endpoint.nodeId,
|
|
455
|
-
endpointIndex: this.endpoint.index,
|
|
456
|
-
...params,
|
|
457
|
-
echo: true,
|
|
458
|
-
});
|
|
459
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
460
|
-
}
|
|
461
|
-
/** Confirms the keys that were granted by the including node */
|
|
462
|
-
async confirmGrantedKeys(params) {
|
|
463
|
-
this.assertSupportsCommand(Security2Command, Security2Command.KEXSet);
|
|
464
|
-
const cc = new Security2CCKEXSet({
|
|
465
|
-
nodeId: this.endpoint.nodeId,
|
|
466
|
-
endpointIndex: this.endpoint.index,
|
|
467
|
-
...params,
|
|
468
|
-
echo: true,
|
|
469
|
-
});
|
|
470
|
-
return this.host.sendCommand(cc, this.commandOptions);
|
|
471
|
-
}
|
|
472
|
-
/** Notifies the other node that the ongoing key exchange was aborted */
|
|
473
|
-
async abortKeyExchange(failType) {
|
|
474
|
-
this.assertSupportsCommand(Security2Command, Security2Command.KEXFail);
|
|
475
|
-
const cc = new Security2CCKEXFail({
|
|
476
|
-
nodeId: this.endpoint.nodeId,
|
|
477
|
-
endpointIndex: this.endpoint.index,
|
|
478
|
-
failType,
|
|
479
|
-
});
|
|
480
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
481
|
-
}
|
|
482
|
-
async sendPublicKey(publicKey, includingNode = true) {
|
|
483
|
-
this.assertSupportsCommand(Security2Command, Security2Command.PublicKeyReport);
|
|
484
|
-
const cc = new Security2CCPublicKeyReport({
|
|
485
|
-
nodeId: this.endpoint.nodeId,
|
|
486
|
-
endpointIndex: this.endpoint.index,
|
|
487
|
-
includingNode,
|
|
488
|
-
publicKey,
|
|
489
|
-
});
|
|
490
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
491
|
-
}
|
|
492
|
-
async requestNetworkKey(securityClass) {
|
|
493
|
-
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyGet);
|
|
494
|
-
const cc = new Security2CCNetworkKeyGet({
|
|
495
|
-
nodeId: this.endpoint.nodeId,
|
|
496
|
-
endpointIndex: this.endpoint.index,
|
|
497
|
-
requestedKey: securityClass,
|
|
498
|
-
});
|
|
499
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
500
|
-
}
|
|
501
|
-
async sendNetworkKey(securityClass, networkKey) {
|
|
502
|
-
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyReport);
|
|
503
|
-
const cc = new Security2CCNetworkKeyReport({
|
|
504
|
-
nodeId: this.endpoint.nodeId,
|
|
505
|
-
endpointIndex: this.endpoint.index,
|
|
506
|
-
grantedKey: securityClass,
|
|
507
|
-
networkKey,
|
|
508
|
-
});
|
|
509
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
510
|
-
}
|
|
511
|
-
async verifyNetworkKey() {
|
|
512
|
-
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyVerify);
|
|
513
|
-
const cc = new Security2CCNetworkKeyVerify({
|
|
514
|
-
nodeId: this.endpoint.nodeId,
|
|
515
|
-
endpointIndex: this.endpoint.index,
|
|
516
|
-
});
|
|
517
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
518
|
-
}
|
|
519
|
-
async confirmKeyVerification() {
|
|
520
|
-
this.assertSupportsCommand(Security2Command, Security2Command.TransferEnd);
|
|
521
|
-
const cc = new Security2CCTransferEnd({
|
|
522
|
-
nodeId: this.endpoint.nodeId,
|
|
523
|
-
endpointIndex: this.endpoint.index,
|
|
524
|
-
keyVerified: true,
|
|
525
|
-
keyRequestComplete: false,
|
|
526
|
-
});
|
|
527
|
-
await this.host.sendCommand(cc, {
|
|
528
|
-
...this.commandOptions,
|
|
529
|
-
// Don't wait for an ACK from the node
|
|
530
|
-
transmitOptions: TransmitOptions.DEFAULT & ~TransmitOptions.ACK,
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
async endKeyExchange() {
|
|
534
|
-
this.assertSupportsCommand(Security2Command, Security2Command.TransferEnd);
|
|
535
|
-
const cc = new Security2CCTransferEnd({
|
|
536
|
-
nodeId: this.endpoint.nodeId,
|
|
537
|
-
endpointIndex: this.endpoint.index,
|
|
538
|
-
keyVerified: false,
|
|
539
|
-
keyRequestComplete: true,
|
|
540
|
-
});
|
|
541
|
-
await this.host.sendCommand(cc, this.commandOptions);
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
Security2CCAPI = __decorate([
|
|
545
|
-
API(CommandClasses["Security 2"])
|
|
546
|
-
], Security2CCAPI);
|
|
547
|
-
export { Security2CCAPI };
|
|
548
|
-
let Security2CC = Security2CC_1 = class Security2CC extends CommandClass {
|
|
549
|
-
async interview(ctx) {
|
|
550
|
-
const securityManager = getSecurityManager(ctx.ownNodeId, ctx, this.nodeId);
|
|
551
|
-
const node = this.getNode(ctx);
|
|
552
|
-
const endpoint = this.getEndpoint(ctx);
|
|
553
|
-
const api = CCAPI.create(CommandClasses["Security 2"], ctx, endpoint).withOptions({
|
|
554
|
-
priority: MessagePriority.NodeQuery,
|
|
555
|
-
});
|
|
556
|
-
// Only on the highest security class the response includes the supported commands
|
|
557
|
-
const secClass = node.getHighestSecurityClass();
|
|
558
|
-
let hasReceivedSecureCommands = false;
|
|
559
|
-
let possibleSecurityClasses;
|
|
560
|
-
if (securityClassIsS2(secClass)) {
|
|
561
|
-
// The highest security class is known to be S2, only query that one
|
|
562
|
-
possibleSecurityClasses = [secClass];
|
|
563
|
-
}
|
|
564
|
-
else if (endpoint.index === 0) {
|
|
565
|
-
// If the highest security class isn't known, query all possible security classes
|
|
566
|
-
// but only on the root device
|
|
567
|
-
possibleSecurityClasses = [
|
|
568
|
-
SecurityClass.S2_Unauthenticated,
|
|
569
|
-
SecurityClass.S2_Authenticated,
|
|
570
|
-
SecurityClass.S2_AccessControl,
|
|
571
|
-
];
|
|
480
|
+
/** Grants the joining node the given keys */
|
|
481
|
+
async grantKeys(params) {
|
|
482
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXSet);
|
|
483
|
+
const cc = new Security2CCKEXSet({
|
|
484
|
+
nodeId: this.endpoint.nodeId,
|
|
485
|
+
endpointIndex: this.endpoint.index,
|
|
486
|
+
...params,
|
|
487
|
+
echo: false,
|
|
488
|
+
});
|
|
489
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
572
490
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
491
|
+
/** Confirms the keys that were requested by a node */
|
|
492
|
+
async confirmRequestedKeys(params) {
|
|
493
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXReport);
|
|
494
|
+
const cc = new Security2CCKEXReport({
|
|
495
|
+
nodeId: this.endpoint.nodeId,
|
|
496
|
+
endpointIndex: this.endpoint.index,
|
|
497
|
+
...params,
|
|
498
|
+
echo: true,
|
|
579
499
|
});
|
|
580
|
-
|
|
500
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
581
501
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
502
|
+
/** Confirms the keys that were granted by the including node */
|
|
503
|
+
async confirmGrantedKeys(params) {
|
|
504
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXSet);
|
|
505
|
+
const cc = new Security2CCKEXSet({
|
|
506
|
+
nodeId: this.endpoint.nodeId,
|
|
507
|
+
endpointIndex: this.endpoint.index,
|
|
508
|
+
...params,
|
|
509
|
+
echo: true,
|
|
510
|
+
});
|
|
511
|
+
return this.host.sendCommand(cc, this.commandOptions);
|
|
512
|
+
}
|
|
513
|
+
/** Notifies the other node that the ongoing key exchange was aborted */
|
|
514
|
+
async abortKeyExchange(failType) {
|
|
515
|
+
this.assertSupportsCommand(Security2Command, Security2Command.KEXFail);
|
|
516
|
+
const cc = new Security2CCKEXFail({
|
|
517
|
+
nodeId: this.endpoint.nodeId,
|
|
518
|
+
endpointIndex: this.endpoint.index,
|
|
519
|
+
failType,
|
|
520
|
+
});
|
|
521
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
522
|
+
}
|
|
523
|
+
async sendPublicKey(publicKey, includingNode = true) {
|
|
524
|
+
this.assertSupportsCommand(Security2Command, Security2Command.PublicKeyReport);
|
|
525
|
+
const cc = new Security2CCPublicKeyReport({
|
|
526
|
+
nodeId: this.endpoint.nodeId,
|
|
527
|
+
endpointIndex: this.endpoint.index,
|
|
528
|
+
includingNode,
|
|
529
|
+
publicKey,
|
|
530
|
+
});
|
|
531
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
532
|
+
}
|
|
533
|
+
async requestNetworkKey(securityClass) {
|
|
534
|
+
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyGet);
|
|
535
|
+
const cc = new Security2CCNetworkKeyGet({
|
|
536
|
+
nodeId: this.endpoint.nodeId,
|
|
537
|
+
endpointIndex: this.endpoint.index,
|
|
538
|
+
requestedKey: securityClass,
|
|
539
|
+
});
|
|
540
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
541
|
+
}
|
|
542
|
+
async sendNetworkKey(securityClass, networkKey) {
|
|
543
|
+
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyReport);
|
|
544
|
+
const cc = new Security2CCNetworkKeyReport({
|
|
545
|
+
nodeId: this.endpoint.nodeId,
|
|
546
|
+
endpointIndex: this.endpoint.index,
|
|
547
|
+
grantedKey: securityClass,
|
|
548
|
+
networkKey,
|
|
549
|
+
});
|
|
550
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
551
|
+
}
|
|
552
|
+
async verifyNetworkKey() {
|
|
553
|
+
this.assertSupportsCommand(Security2Command, Security2Command.NetworkKeyVerify);
|
|
554
|
+
const cc = new Security2CCNetworkKeyVerify({
|
|
555
|
+
nodeId: this.endpoint.nodeId,
|
|
556
|
+
endpointIndex: this.endpoint.index,
|
|
557
|
+
});
|
|
558
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
559
|
+
}
|
|
560
|
+
async confirmKeyVerification() {
|
|
561
|
+
this.assertSupportsCommand(Security2Command, Security2Command.TransferEnd);
|
|
562
|
+
const cc = new Security2CCTransferEnd({
|
|
563
|
+
nodeId: this.endpoint.nodeId,
|
|
564
|
+
endpointIndex: this.endpoint.index,
|
|
565
|
+
keyVerified: true,
|
|
566
|
+
keyRequestComplete: false,
|
|
567
|
+
});
|
|
568
|
+
await this.host.sendCommand(cc, {
|
|
569
|
+
...this.commandOptions,
|
|
570
|
+
// Don't wait for an ACK from the node
|
|
571
|
+
transmitOptions: TransmitOptions.DEFAULT & ~TransmitOptions.ACK,
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
async endKeyExchange() {
|
|
575
|
+
this.assertSupportsCommand(Security2Command, Security2Command.TransferEnd);
|
|
576
|
+
const cc = new Security2CCTransferEnd({
|
|
577
|
+
nodeId: this.endpoint.nodeId,
|
|
578
|
+
endpointIndex: this.endpoint.index,
|
|
579
|
+
keyVerified: false,
|
|
580
|
+
keyRequestComplete: true,
|
|
581
|
+
});
|
|
582
|
+
await this.host.sendCommand(cc, this.commandOptions);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
return Security2CCAPI = _classThis;
|
|
586
|
+
})();
|
|
587
|
+
export { Security2CCAPI };
|
|
588
|
+
let Security2CC = (() => {
|
|
589
|
+
let _classDecorators = [commandClass(CommandClasses["Security 2"]), implementedVersion(1)];
|
|
590
|
+
let _classDescriptor;
|
|
591
|
+
let _classExtraInitializers = [];
|
|
592
|
+
let _classThis;
|
|
593
|
+
let _classSuper = CommandClass;
|
|
594
|
+
var Security2CC = class extends _classSuper {
|
|
595
|
+
static { _classThis = this; }
|
|
596
|
+
static {
|
|
597
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
598
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
599
|
+
Security2CC = _classThis = _classDescriptor.value;
|
|
600
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
601
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
602
|
+
}
|
|
603
|
+
async interview(ctx) {
|
|
604
|
+
const securityManager = getSecurityManager(ctx.ownNodeId, ctx, this.nodeId);
|
|
605
|
+
const node = this.getNode(ctx);
|
|
606
|
+
const endpoint = this.getEndpoint(ctx);
|
|
607
|
+
const api = CCAPI.create(CommandClasses["Security 2"], ctx, endpoint).withOptions({
|
|
608
|
+
priority: MessagePriority.NodeQuery,
|
|
609
|
+
});
|
|
610
|
+
// Only on the highest security class the response includes the supported commands
|
|
611
|
+
const secClass = node.getHighestSecurityClass();
|
|
612
|
+
let hasReceivedSecureCommands = false;
|
|
613
|
+
let possibleSecurityClasses;
|
|
614
|
+
if (securityClassIsS2(secClass)) {
|
|
615
|
+
// The highest security class is known to be S2, only query that one
|
|
616
|
+
possibleSecurityClasses = [secClass];
|
|
617
|
+
}
|
|
618
|
+
else if (endpoint.index === 0) {
|
|
619
|
+
// If the highest security class isn't known, query all possible security classes
|
|
620
|
+
// but only on the root device
|
|
621
|
+
possibleSecurityClasses = [
|
|
622
|
+
SecurityClass.S2_Unauthenticated,
|
|
623
|
+
SecurityClass.S2_Authenticated,
|
|
624
|
+
SecurityClass.S2_AccessControl,
|
|
625
|
+
];
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
// For endpoint interviews, the security class MUST be known
|
|
593
629
|
ctx.logNode(node.id, {
|
|
594
630
|
endpoint: endpoint.index,
|
|
595
|
-
message: `Cannot query securely supported commands
|
|
596
|
-
level: "
|
|
631
|
+
message: `Cannot query securely supported commands for endpoint because the node's security class isn't known...`,
|
|
632
|
+
level: "error",
|
|
597
633
|
});
|
|
598
|
-
|
|
634
|
+
return;
|
|
599
635
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
636
|
+
for (const secClass of possibleSecurityClasses) {
|
|
637
|
+
// We might not know all assigned security classes yet, so we work our way up from low to high and try to request the supported commands.
|
|
638
|
+
// This way, each command is encrypted with the security class we're currently testing.
|
|
639
|
+
// If the node does not respond, it wasn't assigned the security class.
|
|
640
|
+
// If it responds with a non-empty list, we know this is the highest class it supports.
|
|
641
|
+
// If the list is empty, the security class is still supported.
|
|
642
|
+
// If we already know the class is not supported, skip it
|
|
643
|
+
if (node.hasSecurityClass(secClass) === false)
|
|
644
|
+
continue;
|
|
645
|
+
// If no key is configured for this security class, skip it
|
|
646
|
+
if (!securityManager?.hasKeysForSecurityClass(secClass)) {
|
|
647
|
+
ctx.logNode(node.id, {
|
|
648
|
+
endpoint: endpoint.index,
|
|
649
|
+
message: `Cannot query securely supported commands (${getEnumMemberName(SecurityClass, secClass)}) - network key is not configured...`,
|
|
650
|
+
level: "warn",
|
|
651
|
+
});
|
|
652
|
+
continue;
|
|
612
653
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
654
|
+
ctx.logNode(node.id, {
|
|
655
|
+
endpoint: endpoint.index,
|
|
656
|
+
message: `Querying securely supported commands (${getEnumMemberName(SecurityClass, secClass)})...`,
|
|
657
|
+
direction: "outbound",
|
|
658
|
+
});
|
|
659
|
+
// Query the supported commands but avoid remembering the wrong security class in case of a failure
|
|
660
|
+
let supportedCCs;
|
|
661
|
+
// Try up to 3 times on the root device. We REALLY don't want a spurious timeout or collision to cause us to discard a known good security class
|
|
662
|
+
const MAX_ATTEMPTS = this.endpointIndex === 0 ? 3 : 1;
|
|
663
|
+
for (let attempts = 1; attempts <= MAX_ATTEMPTS; attempts++) {
|
|
664
|
+
try {
|
|
665
|
+
supportedCCs = await api.getSupportedCommands(secClass);
|
|
622
666
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
await wait(500);
|
|
634
|
-
continue;
|
|
667
|
+
catch (e) {
|
|
668
|
+
if (isZWaveError(e)
|
|
669
|
+
&& e.code === ZWaveErrorCodes.Security2CC_CannotDecode) {
|
|
670
|
+
// Either we were using a non-granted security class,
|
|
671
|
+
// or querying with the known highest security class had an issue
|
|
672
|
+
supportedCCs = undefined;
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
throw e;
|
|
676
|
+
}
|
|
635
677
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
678
|
+
if (supportedCCs == undefined
|
|
679
|
+
&& possibleSecurityClasses.length === 1) {
|
|
680
|
+
if (attempts < MAX_ATTEMPTS) {
|
|
681
|
+
// We definitely know the highest security class
|
|
682
|
+
ctx.logNode(node.id, {
|
|
683
|
+
endpoint: endpoint.index,
|
|
684
|
+
message: `Querying securely supported commands (${getEnumMemberName(SecurityClass, secClass)}), attempt ${attempts}/${MAX_ATTEMPTS} failed. Retrying in 500ms...`,
|
|
685
|
+
level: "warn",
|
|
686
|
+
});
|
|
687
|
+
await wait(500);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
else if (endpoint.index > 0) {
|
|
691
|
+
ctx.logNode(node.id, {
|
|
692
|
+
endpoint: endpoint.index,
|
|
693
|
+
message: `Querying securely supported commands (${getEnumMemberName(SecurityClass, secClass)}) failed. Assuming the endpoint supports all its mandatory CCs securely...`,
|
|
694
|
+
level: "warn",
|
|
695
|
+
});
|
|
696
|
+
// Just mark all endpoint CCs as secure. Without this we would attempt
|
|
697
|
+
// unencrypted communication with the endpoint, which will likely fail.
|
|
698
|
+
for (const [ccId] of endpoint.getCCs()) {
|
|
699
|
+
endpoint.addCC(ccId, { secure: true });
|
|
700
|
+
}
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
ctx.logNode(node.id, {
|
|
705
|
+
endpoint: endpoint.index,
|
|
706
|
+
message: `Querying securely supported commands (${getEnumMemberName(SecurityClass, secClass)}) failed. Let's hope for the best...`,
|
|
707
|
+
level: "warn",
|
|
708
|
+
});
|
|
709
|
+
break;
|
|
646
710
|
}
|
|
647
|
-
break;
|
|
648
711
|
}
|
|
649
712
|
else {
|
|
650
|
-
|
|
651
|
-
endpoint: endpoint.index,
|
|
652
|
-
message: `Querying securely supported commands (${getEnumMemberName(SecurityClass, secClass)}) failed. Let's hope for the best...`,
|
|
653
|
-
level: "warn",
|
|
654
|
-
});
|
|
713
|
+
// In any other case, we can stop trying
|
|
655
714
|
break;
|
|
656
715
|
}
|
|
657
716
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
717
|
+
if (supportedCCs == undefined) {
|
|
718
|
+
if (endpoint.index === 0
|
|
719
|
+
&& possibleSecurityClasses.length > 1) {
|
|
720
|
+
// No supported commands found, mark the security class as not granted
|
|
721
|
+
// unless we were sure about the security class
|
|
722
|
+
node.setSecurityClass(secClass, false);
|
|
723
|
+
ctx.logNode(node.id, {
|
|
724
|
+
message: `The node was NOT granted the security class ${getEnumMemberName(SecurityClass, secClass)}`,
|
|
725
|
+
direction: "inbound",
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
continue;
|
|
661
729
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
&& possibleSecurityClasses.length > 1) {
|
|
666
|
-
// No supported commands found, mark the security class as not granted
|
|
667
|
-
// unless we were sure about the security class
|
|
668
|
-
node.setSecurityClass(secClass, false);
|
|
730
|
+
if (endpoint.index === 0 && possibleSecurityClasses.length > 1) {
|
|
731
|
+
// Mark the security class as granted unless we were sure about the security class
|
|
732
|
+
node.setSecurityClass(secClass, true);
|
|
669
733
|
ctx.logNode(node.id, {
|
|
670
|
-
message: `The node was
|
|
734
|
+
message: `The node was granted the security class ${getEnumMemberName(SecurityClass, secClass)}`,
|
|
671
735
|
direction: "inbound",
|
|
672
736
|
});
|
|
673
737
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
if (!hasReceivedSecureCommands && supportedCCs.length > 0) {
|
|
685
|
-
hasReceivedSecureCommands = true;
|
|
686
|
-
const logLines = [
|
|
687
|
-
`received secure commands (${getEnumMemberName(SecurityClass, secClass)})`,
|
|
688
|
-
"supported CCs:",
|
|
689
|
-
];
|
|
690
|
-
for (const cc of supportedCCs) {
|
|
691
|
-
logLines.push(`· ${getCCName(cc)}`);
|
|
692
|
-
}
|
|
693
|
-
ctx.logNode(node.id, {
|
|
694
|
-
endpoint: endpoint.index,
|
|
695
|
-
message: logLines.join("\n"),
|
|
696
|
-
direction: "inbound",
|
|
697
|
-
});
|
|
698
|
-
// Remember which commands are supported securely
|
|
699
|
-
for (const cc of supportedCCs) {
|
|
700
|
-
// Basic CC has special rules for when it is considered supported
|
|
701
|
-
// Therefore we mark all other CCs as supported, but not Basic CC,
|
|
702
|
-
// for which support is determined later.
|
|
703
|
-
if (cc === CommandClasses.Basic) {
|
|
704
|
-
endpoint.addCC(cc, { secure: true });
|
|
738
|
+
if (!hasReceivedSecureCommands && supportedCCs.length > 0) {
|
|
739
|
+
hasReceivedSecureCommands = true;
|
|
740
|
+
const logLines = [
|
|
741
|
+
`received secure commands (${getEnumMemberName(SecurityClass, secClass)})`,
|
|
742
|
+
"supported CCs:",
|
|
743
|
+
];
|
|
744
|
+
for (const cc of supportedCCs) {
|
|
745
|
+
logLines.push(`· ${getCCName(cc)}`);
|
|
705
746
|
}
|
|
706
|
-
|
|
707
|
-
endpoint.
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
747
|
+
ctx.logNode(node.id, {
|
|
748
|
+
endpoint: endpoint.index,
|
|
749
|
+
message: logLines.join("\n"),
|
|
750
|
+
direction: "inbound",
|
|
751
|
+
});
|
|
752
|
+
// Remember which commands are supported securely
|
|
753
|
+
for (const cc of supportedCCs) {
|
|
754
|
+
// Basic CC has special rules for when it is considered supported
|
|
755
|
+
// Therefore we mark all other CCs as supported, but not Basic CC,
|
|
756
|
+
// for which support is determined later.
|
|
757
|
+
if (cc === CommandClasses.Basic) {
|
|
758
|
+
endpoint.addCC(cc, { secure: true });
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
endpoint.addCC(cc, {
|
|
762
|
+
isSupported: true,
|
|
763
|
+
secure: true,
|
|
764
|
+
});
|
|
765
|
+
}
|
|
711
766
|
}
|
|
712
767
|
}
|
|
713
768
|
}
|
|
769
|
+
// Remember that the interview is complete
|
|
770
|
+
this.setInterviewComplete(ctx, true);
|
|
714
771
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
default:
|
|
754
|
-
return false;
|
|
772
|
+
/** Tests if a command should be sent secure and thus requires encapsulation */
|
|
773
|
+
static requiresEncapsulation(cc) {
|
|
774
|
+
// No security flag -> no encapsulation
|
|
775
|
+
if (!(cc.encapsulationFlags & EncapsulationFlags.Security)) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
// S0, CRC16, Transport Service -> no S2 encapsulation
|
|
779
|
+
if (cc instanceof SecurityCC
|
|
780
|
+
|| cc instanceof CRC16CC
|
|
781
|
+
|| cc instanceof TransportServiceCC) {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
// S2: check command
|
|
785
|
+
if (cc instanceof Security2CC) {
|
|
786
|
+
// These S2 commands need additional encapsulation
|
|
787
|
+
switch (cc.ccCommand) {
|
|
788
|
+
case Security2Command.CommandsSupportedGet:
|
|
789
|
+
case Security2Command.CommandsSupportedReport:
|
|
790
|
+
case Security2Command.NetworkKeyGet:
|
|
791
|
+
case Security2Command.NetworkKeyReport:
|
|
792
|
+
case Security2Command.NetworkKeyVerify:
|
|
793
|
+
case Security2Command.TransferEnd:
|
|
794
|
+
return true;
|
|
795
|
+
case Security2Command.KEXSet:
|
|
796
|
+
case Security2Command.KEXReport:
|
|
797
|
+
// KEXSet/Report need to be encrypted for the confirmation only
|
|
798
|
+
return cc
|
|
799
|
+
.echo;
|
|
800
|
+
case Security2Command.KEXFail: {
|
|
801
|
+
switch (cc.failType) {
|
|
802
|
+
case KEXFailType.Decrypt:
|
|
803
|
+
case KEXFailType.WrongSecurityLevel:
|
|
804
|
+
case KEXFailType.KeyNotGranted:
|
|
805
|
+
case KEXFailType.NoVerify:
|
|
806
|
+
return true;
|
|
807
|
+
default:
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
755
810
|
}
|
|
756
811
|
}
|
|
812
|
+
return false;
|
|
757
813
|
}
|
|
758
|
-
|
|
814
|
+
// Everything else needs to be encapsulated if the CC is secure
|
|
815
|
+
return true;
|
|
759
816
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
817
|
+
/** Encapsulates a command that should be sent encrypted */
|
|
818
|
+
static encapsulate(cc, ownNodeId, securityManagers, options) {
|
|
819
|
+
// Determine which extensions must be used on the command
|
|
820
|
+
const extensions = [];
|
|
821
|
+
if (options?.multicastOutOfSync) {
|
|
822
|
+
extensions.push(new MOSExtension());
|
|
823
|
+
}
|
|
824
|
+
if (options?.multicastGroupId != undefined) {
|
|
825
|
+
extensions.push(new MGRPExtension({ groupId: options.multicastGroupId }));
|
|
826
|
+
}
|
|
827
|
+
// Make sure that S2 multicast uses broadcasts. While the specs mention that both multicast and broadcast
|
|
828
|
+
// are possible, it has been found that devices treat multicasts like singlecast followups and respond incorrectly.
|
|
829
|
+
let nodeId;
|
|
830
|
+
if (cc.isMulticast()) {
|
|
831
|
+
if (cc.nodeId.some((nodeId) => isLongRangeNodeId(nodeId))) {
|
|
832
|
+
nodeId = NODE_ID_BROADCAST_LR;
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
nodeId = NODE_ID_BROADCAST;
|
|
836
|
+
}
|
|
779
837
|
}
|
|
780
838
|
else {
|
|
781
|
-
nodeId =
|
|
839
|
+
nodeId = cc.nodeId;
|
|
782
840
|
}
|
|
841
|
+
const ret = new Security2CCMessageEncapsulation({
|
|
842
|
+
nodeId,
|
|
843
|
+
encapsulated: cc,
|
|
844
|
+
securityClass: options?.securityClass,
|
|
845
|
+
extensions,
|
|
846
|
+
verifyDelivery: options?.verifyDelivery,
|
|
847
|
+
});
|
|
848
|
+
// Copy the encapsulation flags from the encapsulated command
|
|
849
|
+
// but omit Security, since we're doing that right now
|
|
850
|
+
ret.encapsulationFlags = cc.encapsulationFlags
|
|
851
|
+
& ~EncapsulationFlags.Security;
|
|
852
|
+
return ret;
|
|
783
853
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const ret = new Security2CCMessageEncapsulation({
|
|
788
|
-
nodeId,
|
|
789
|
-
encapsulated: cc,
|
|
790
|
-
securityClass: options?.securityClass,
|
|
791
|
-
extensions,
|
|
792
|
-
verifyDelivery: options?.verifyDelivery,
|
|
793
|
-
});
|
|
794
|
-
// Copy the encapsulation flags from the encapsulated command
|
|
795
|
-
// but omit Security, since we're doing that right now
|
|
796
|
-
ret.encapsulationFlags = cc.encapsulationFlags
|
|
797
|
-
& ~EncapsulationFlags.Security;
|
|
798
|
-
return ret;
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
Security2CC = Security2CC_1 = __decorate([
|
|
802
|
-
commandClass(CommandClasses["Security 2"]),
|
|
803
|
-
implementedVersion(1)
|
|
804
|
-
], Security2CC);
|
|
854
|
+
};
|
|
855
|
+
return Security2CC = _classThis;
|
|
856
|
+
})();
|
|
805
857
|
export { Security2CC };
|
|
806
858
|
function failNoSPAN() {
|
|
807
859
|
validatePayload.fail(ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
@@ -837,657 +889,719 @@ function testCCResponseForMessageEncapsulation(sent, received) {
|
|
|
837
889
|
return received.SOS && !!received.receiverEI;
|
|
838
890
|
}
|
|
839
891
|
}
|
|
840
|
-
let Security2CCMessageEncapsulation =
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
if (typeof this.nodeId !== "number"
|
|
855
|
-
&& !this.extensions.some((e) => e instanceof MGRPExtension)) {
|
|
856
|
-
throw new ZWaveError("Multicast Security S2 encapsulation requires the MGRP extension", ZWaveErrorCodes.Security2CC_MissingExtension);
|
|
892
|
+
let Security2CCMessageEncapsulation = (() => {
|
|
893
|
+
let _classDecorators = [CCCommand(Security2Command.MessageEncapsulation), expectedCCResponse(getCCResponseForMessageEncapsulation, testCCResponseForMessageEncapsulation)];
|
|
894
|
+
let _classDescriptor;
|
|
895
|
+
let _classExtraInitializers = [];
|
|
896
|
+
let _classThis;
|
|
897
|
+
let _classSuper = Security2CC;
|
|
898
|
+
var Security2CCMessageEncapsulation = class extends _classSuper {
|
|
899
|
+
static { _classThis = this; }
|
|
900
|
+
static {
|
|
901
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
902
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
903
|
+
Security2CCMessageEncapsulation = _classThis = _classDescriptor.value;
|
|
904
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
905
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
857
906
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
907
|
+
constructor(options) {
|
|
908
|
+
super(options);
|
|
909
|
+
if (!options.encapsulated && !options.extensions?.length) {
|
|
910
|
+
throw new ZWaveError("Security S2 encapsulation requires an encapsulated CC and/or extensions", ZWaveErrorCodes.Argument_Invalid);
|
|
911
|
+
}
|
|
912
|
+
this.sequenceNumber = options.sequenceNumber;
|
|
913
|
+
this.securityClass = options.securityClass;
|
|
914
|
+
if (options.encapsulated) {
|
|
915
|
+
this.encapsulated = options.encapsulated;
|
|
916
|
+
options.encapsulated.encapsulatingCC = this;
|
|
917
|
+
}
|
|
918
|
+
this.verifyDelivery = options.verifyDelivery !== false;
|
|
919
|
+
this.extensions = options.extensions ?? [];
|
|
920
|
+
if (typeof this.nodeId !== "number"
|
|
921
|
+
&& !this.extensions.some((e) => e instanceof MGRPExtension)) {
|
|
922
|
+
throw new ZWaveError("Multicast Security S2 encapsulation requires the MGRP extension", ZWaveErrorCodes.Security2CC_MissingExtension);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
static from(raw, ctx) {
|
|
926
|
+
const securityManager = assertSecurityRX(ctx);
|
|
927
|
+
validatePayload(raw.payload.length >= 2);
|
|
928
|
+
// Check the sequence number to avoid duplicates
|
|
929
|
+
const sequenceNumber = raw.payload[0];
|
|
930
|
+
// Ensure the node has a security class
|
|
931
|
+
validatePayload.withReason("No security class granted")(ctx.getHighestSecurityClass(ctx.sourceNodeId) !== SecurityClass.None);
|
|
932
|
+
const hasExtensions = !!(raw.payload[1] & 0b1);
|
|
933
|
+
const hasEncryptedExtensions = !!(raw.payload[1] & 0b10);
|
|
934
|
+
let offset = 2;
|
|
935
|
+
const extensions = [];
|
|
936
|
+
let mustDiscardCommand = false;
|
|
937
|
+
const parseExtensions = (buffer, wasEncrypted) => {
|
|
938
|
+
while (true) {
|
|
939
|
+
if (buffer.length < offset + 2) {
|
|
940
|
+
// An S2 extension was expected, but the buffer is too short
|
|
941
|
+
mustDiscardCommand = true;
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
// The length field could be too large, which would cause part of the actual ciphertext
|
|
945
|
+
// to be ignored. Try to avoid this for known extensions by checking the actual and expected length.
|
|
946
|
+
const { actual: actualLength, expected: expectedLength } = Security2Extension
|
|
947
|
+
.getExtensionLength(buffer.subarray(offset));
|
|
948
|
+
// Parse the extension using the expected length if possible
|
|
949
|
+
const extensionLength = expectedLength ?? actualLength;
|
|
950
|
+
if (extensionLength < 2) {
|
|
951
|
+
// An S2 extension was expected, but the length is too short
|
|
952
|
+
mustDiscardCommand = true;
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
else if (extensionLength
|
|
956
|
+
> buffer.length
|
|
957
|
+
- offset
|
|
958
|
+
- (wasEncrypted
|
|
959
|
+
? 0
|
|
960
|
+
: SECURITY_S2_AUTH_TAG_LENGTH)) {
|
|
961
|
+
// The supposed length is longer than the space the extensions may occupy
|
|
962
|
+
mustDiscardCommand = true;
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const extensionData = buffer.subarray(offset, offset + extensionLength);
|
|
966
|
+
offset += extensionLength;
|
|
967
|
+
const ext = Security2Extension.parse(extensionData);
|
|
968
|
+
switch (validateS2Extension(ext, wasEncrypted)) {
|
|
969
|
+
case ValidateS2ExtensionResult.OK:
|
|
970
|
+
if (expectedLength != undefined
|
|
971
|
+
&& actualLength !== expectedLength) {
|
|
972
|
+
// The extension length field does not match, ignore the extension
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
extensions.push(ext);
|
|
976
|
+
}
|
|
977
|
+
break;
|
|
978
|
+
case ValidateS2ExtensionResult.DiscardExtension:
|
|
979
|
+
// Do nothing
|
|
980
|
+
break;
|
|
981
|
+
case ValidateS2ExtensionResult.DiscardCommand:
|
|
982
|
+
mustDiscardCommand = true;
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
// Check if that was the last extension
|
|
986
|
+
if (!ext.moreToFollow)
|
|
987
|
+
break;
|
|
877
988
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
return
|
|
989
|
+
};
|
|
990
|
+
if (hasExtensions)
|
|
991
|
+
parseExtensions(raw.payload, false);
|
|
992
|
+
const mcctx = (() => {
|
|
993
|
+
const multicastGroupId = getMulticastGroupId(extensions);
|
|
994
|
+
if (ctx.frameType === "multicast" || ctx.frameType === "broadcast") {
|
|
995
|
+
if (multicastGroupId == undefined) {
|
|
996
|
+
validatePayload.fail("Multicast frames without MGRP extension");
|
|
997
|
+
}
|
|
998
|
+
return {
|
|
999
|
+
isMulticast: true,
|
|
1000
|
+
groupId: multicastGroupId,
|
|
1001
|
+
};
|
|
888
1002
|
}
|
|
889
|
-
else
|
|
890
|
-
|
|
891
|
-
- offset
|
|
892
|
-
- (wasEncrypted
|
|
893
|
-
? 0
|
|
894
|
-
: SECURITY_S2_AUTH_TAG_LENGTH)) {
|
|
895
|
-
// The supposed length is longer than the space the extensions may occupy
|
|
896
|
-
mustDiscardCommand = true;
|
|
897
|
-
return;
|
|
1003
|
+
else {
|
|
1004
|
+
return { isMulticast: false, groupId: multicastGroupId };
|
|
898
1005
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
&& actualLength !== expectedLength) {
|
|
906
|
-
// The extension length field does not match, ignore the extension
|
|
907
|
-
}
|
|
908
|
-
else {
|
|
909
|
-
extensions.push(ext);
|
|
910
|
-
}
|
|
911
|
-
break;
|
|
912
|
-
case ValidateS2ExtensionResult.DiscardExtension:
|
|
913
|
-
// Do nothing
|
|
914
|
-
break;
|
|
915
|
-
case ValidateS2ExtensionResult.DiscardCommand:
|
|
916
|
-
mustDiscardCommand = true;
|
|
917
|
-
break;
|
|
1006
|
+
})();
|
|
1007
|
+
// If a command is to be discarded before decryption,
|
|
1008
|
+
// we still need to increment the SPAN or MPAN state
|
|
1009
|
+
if (mustDiscardCommand) {
|
|
1010
|
+
if (mcctx.isMulticast) {
|
|
1011
|
+
securityManager.nextPeerMPAN(ctx.sourceNodeId, mcctx.groupId);
|
|
918
1012
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
break;
|
|
922
|
-
}
|
|
923
|
-
};
|
|
924
|
-
if (hasExtensions)
|
|
925
|
-
parseExtensions(raw.payload, false);
|
|
926
|
-
const mcctx = (() => {
|
|
927
|
-
const multicastGroupId = getMulticastGroupId(extensions);
|
|
928
|
-
if (ctx.frameType === "multicast" || ctx.frameType === "broadcast") {
|
|
929
|
-
if (multicastGroupId == undefined) {
|
|
930
|
-
validatePayload.fail("Multicast frames without MGRP extension");
|
|
1013
|
+
else {
|
|
1014
|
+
securityManager.nextNonce(ctx.sourceNodeId);
|
|
931
1015
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1016
|
+
validatePayload.fail("Invalid S2 extension");
|
|
1017
|
+
}
|
|
1018
|
+
let prevSequenceNumber;
|
|
1019
|
+
let mpanState;
|
|
1020
|
+
if (mcctx.isMulticast) {
|
|
1021
|
+
mpanState = securityManager.getPeerMPAN(ctx.sourceNodeId, mcctx.groupId);
|
|
936
1022
|
}
|
|
937
1023
|
else {
|
|
938
|
-
|
|
1024
|
+
// Don't accept duplicate Singlecast commands
|
|
1025
|
+
prevSequenceNumber = validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1026
|
+
// When a node receives a singlecast message after a multicast group was marked out of sync,
|
|
1027
|
+
// it must forget about the group.
|
|
1028
|
+
if (mcctx.groupId == undefined) {
|
|
1029
|
+
securityManager.resetOutOfSyncMPANs(ctx.sourceNodeId);
|
|
1030
|
+
}
|
|
939
1031
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1032
|
+
const unencryptedPayload = raw.payload.subarray(0, offset);
|
|
1033
|
+
const ciphertext = raw.payload.subarray(offset, -SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1034
|
+
const authTag = raw.payload.subarray(-SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1035
|
+
const messageLength = 2 /* CommandClass.computeEncapsulationOverhead() */
|
|
1036
|
+
+ raw.payload.length;
|
|
1037
|
+
const authData = getAuthenticationData(ctx.sourceNodeId, getDestinationIDRX(ctx, extensions), ctx.homeId, messageLength, unencryptedPayload);
|
|
1038
|
+
let decrypt;
|
|
944
1039
|
if (mcctx.isMulticast) {
|
|
945
|
-
|
|
1040
|
+
// For incoming multicast commands, make sure we have an MPAN
|
|
1041
|
+
if (mpanState?.type !== MPANState.MPAN) {
|
|
1042
|
+
// If we don't, mark the MPAN as out of sync, so we can respond accordingly on the singlecast followup
|
|
1043
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: MPANState.OutOfSync });
|
|
1044
|
+
failNoMPAN();
|
|
1045
|
+
}
|
|
1046
|
+
decrypt = () => decryptMulticast(ctx.sourceNodeId, securityManager, mcctx.groupId, ciphertext, authData, authTag);
|
|
946
1047
|
}
|
|
947
1048
|
else {
|
|
948
|
-
|
|
1049
|
+
// Decrypt payload and verify integrity
|
|
1050
|
+
const spanState = securityManager.getSPANState(ctx.sourceNodeId);
|
|
1051
|
+
// If we are not able to establish an SPAN yet, fail the decryption
|
|
1052
|
+
if (spanState.type === SPANState.None) {
|
|
1053
|
+
failNoSPAN();
|
|
1054
|
+
}
|
|
1055
|
+
else if (spanState.type === SPANState.RemoteEI) {
|
|
1056
|
+
// TODO: The specs are not clear how to handle this case
|
|
1057
|
+
// For now, do the same as if we didn't have any EI
|
|
1058
|
+
failNoSPAN();
|
|
1059
|
+
}
|
|
1060
|
+
decrypt = () => decryptSinglecast(ctx, securityManager, ctx.sourceNodeId, sequenceNumber, prevSequenceNumber, ciphertext, authData, authTag, spanState, extensions);
|
|
949
1061
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
//
|
|
959
|
-
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1062
|
+
let plaintext;
|
|
1063
|
+
let authOK = false;
|
|
1064
|
+
let key;
|
|
1065
|
+
let iv;
|
|
1066
|
+
let decryptionSecurityClass;
|
|
1067
|
+
// If the Receiver is unable to authenticate the singlecast message with the current SPAN,
|
|
1068
|
+
// the Receiver SHOULD try decrypting the message with one or more of the following SPAN values,
|
|
1069
|
+
// stopping when decryption is successful or the maximum number of iterations is reached.
|
|
1070
|
+
// If the Receiver is unable to decrypt the S2 MC frame with the current MPAN, the Receiver MAY try
|
|
1071
|
+
// decrypting the frame with one or more of the subsequent MPAN values, stopping when decryption is
|
|
1072
|
+
// successful or the maximum number of iterations is reached.
|
|
1073
|
+
const decryptAttempts = mcctx.isMulticast
|
|
1074
|
+
? MAX_DECRYPT_ATTEMPTS_MULTICAST
|
|
1075
|
+
: mcctx.groupId != undefined
|
|
1076
|
+
? MAX_DECRYPT_ATTEMPTS_SC_FOLLOWUP
|
|
1077
|
+
: MAX_DECRYPT_ATTEMPTS_SINGLECAST;
|
|
1078
|
+
for (let i = 0; i < decryptAttempts; i++) {
|
|
1079
|
+
({
|
|
1080
|
+
plaintext,
|
|
1081
|
+
authOK,
|
|
1082
|
+
key,
|
|
1083
|
+
iv,
|
|
1084
|
+
securityClass: decryptionSecurityClass,
|
|
1085
|
+
} = decrypt());
|
|
1086
|
+
if (!!authOK && !!plaintext)
|
|
1087
|
+
break;
|
|
1088
|
+
// No need to try further SPANs if we just got the sender's EI
|
|
1089
|
+
if (!!getSenderEI(extensions))
|
|
1090
|
+
break;
|
|
964
1091
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
// If we don't, mark the MPAN as out of sync, so we can respond accordingly on the singlecast followup
|
|
977
|
-
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: MPANState.OutOfSync });
|
|
978
|
-
failNoMPAN();
|
|
1092
|
+
// If authentication fails, do so with an error code that instructs the
|
|
1093
|
+
// applHost to tell the node we have no nonce
|
|
1094
|
+
if (!authOK || !plaintext) {
|
|
1095
|
+
if (mcctx.isMulticast) {
|
|
1096
|
+
// Mark the MPAN as out of sync
|
|
1097
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: MPANState.OutOfSync });
|
|
1098
|
+
validatePayload.fail(ZWaveErrorCodes.Security2CC_CannotDecodeMulticast);
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
validatePayload.fail(ZWaveErrorCodes.Security2CC_CannotDecode);
|
|
1102
|
+
}
|
|
979
1103
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
// Decrypt payload and verify integrity
|
|
984
|
-
const spanState = securityManager.getSPANState(ctx.sourceNodeId);
|
|
985
|
-
// If we are not able to establish an SPAN yet, fail the decryption
|
|
986
|
-
if (spanState.type === SPANState.None) {
|
|
987
|
-
failNoSPAN();
|
|
1104
|
+
else if (!mcctx.isMulticast && mcctx.groupId != undefined) {
|
|
1105
|
+
// After reception of a singlecast followup, the MPAN state must be increased
|
|
1106
|
+
securityManager.tryIncrementPeerMPAN(ctx.sourceNodeId, mcctx.groupId);
|
|
988
1107
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1108
|
+
// Remember which security class was used to decrypt this message, so we can discard it later
|
|
1109
|
+
const securityClass = decryptionSecurityClass;
|
|
1110
|
+
offset = 0;
|
|
1111
|
+
if (hasEncryptedExtensions)
|
|
1112
|
+
parseExtensions(plaintext, true);
|
|
1113
|
+
// Before we can continue, check if the command must be discarded
|
|
1114
|
+
if (mustDiscardCommand) {
|
|
1115
|
+
validatePayload.fail("Invalid extension");
|
|
993
1116
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
// stopping when decryption is successful or the maximum number of iterations is reached.
|
|
1004
|
-
// If the Receiver is unable to decrypt the S2 MC frame with the current MPAN, the Receiver MAY try
|
|
1005
|
-
// decrypting the frame with one or more of the subsequent MPAN values, stopping when decryption is
|
|
1006
|
-
// successful or the maximum number of iterations is reached.
|
|
1007
|
-
const decryptAttempts = mcctx.isMulticast
|
|
1008
|
-
? MAX_DECRYPT_ATTEMPTS_MULTICAST
|
|
1009
|
-
: mcctx.groupId != undefined
|
|
1010
|
-
? MAX_DECRYPT_ATTEMPTS_SC_FOLLOWUP
|
|
1011
|
-
: MAX_DECRYPT_ATTEMPTS_SINGLECAST;
|
|
1012
|
-
for (let i = 0; i < decryptAttempts; i++) {
|
|
1013
|
-
({
|
|
1014
|
-
plaintext,
|
|
1015
|
-
authOK,
|
|
1016
|
-
key,
|
|
1017
|
-
iv,
|
|
1018
|
-
securityClass: decryptionSecurityClass,
|
|
1019
|
-
} = decrypt());
|
|
1020
|
-
if (!!authOK && !!plaintext)
|
|
1021
|
-
break;
|
|
1022
|
-
// No need to try further SPANs if we just got the sender's EI
|
|
1023
|
-
if (!!getSenderEI(extensions))
|
|
1024
|
-
break;
|
|
1025
|
-
}
|
|
1026
|
-
// If authentication fails, do so with an error code that instructs the
|
|
1027
|
-
// applHost to tell the node we have no nonce
|
|
1028
|
-
if (!authOK || !plaintext) {
|
|
1029
|
-
if (mcctx.isMulticast) {
|
|
1030
|
-
// Mark the MPAN as out of sync
|
|
1031
|
-
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: MPANState.OutOfSync });
|
|
1032
|
-
validatePayload.fail(ZWaveErrorCodes.Security2CC_CannotDecodeMulticast);
|
|
1117
|
+
// If the MPAN extension was received, store the MPAN
|
|
1118
|
+
if (!mcctx.isMulticast) {
|
|
1119
|
+
const mpanExtension = extensions.find((e) => e instanceof MPANExtension);
|
|
1120
|
+
if (mpanExtension) {
|
|
1121
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mpanExtension.groupId, {
|
|
1122
|
+
type: MPANState.MPAN,
|
|
1123
|
+
currentMPAN: mpanExtension.innerMPANState,
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1033
1126
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1127
|
+
// Not every S2 message includes an encapsulated CC
|
|
1128
|
+
const decryptedCCBytes = plaintext.subarray(offset);
|
|
1129
|
+
let encapsulated;
|
|
1130
|
+
if (decryptedCCBytes.length > 0) {
|
|
1131
|
+
// make sure this contains a complete CC command that's worth splitting
|
|
1132
|
+
validatePayload(decryptedCCBytes.length >= 2);
|
|
1133
|
+
// and deserialize the CC
|
|
1134
|
+
encapsulated = CommandClass.parse(decryptedCCBytes, ctx);
|
|
1036
1135
|
}
|
|
1136
|
+
const ret = new Security2CCMessageEncapsulation({
|
|
1137
|
+
nodeId: ctx.sourceNodeId,
|
|
1138
|
+
sequenceNumber,
|
|
1139
|
+
securityClass,
|
|
1140
|
+
extensions,
|
|
1141
|
+
encapsulated,
|
|
1142
|
+
});
|
|
1143
|
+
// Remember for debugging purposes
|
|
1144
|
+
ret.key = key;
|
|
1145
|
+
ret.iv = iv;
|
|
1146
|
+
ret.authData = authData;
|
|
1147
|
+
ret.authTag = authTag;
|
|
1148
|
+
ret.plaintext = decryptedCCBytes;
|
|
1149
|
+
return ret;
|
|
1037
1150
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
});
|
|
1151
|
+
securityClass;
|
|
1152
|
+
// Only used for testing/debugging purposes
|
|
1153
|
+
key;
|
|
1154
|
+
iv;
|
|
1155
|
+
authData;
|
|
1156
|
+
authTag;
|
|
1157
|
+
ciphertext;
|
|
1158
|
+
plaintext;
|
|
1159
|
+
verifyDelivery = true;
|
|
1160
|
+
sequenceNumber;
|
|
1161
|
+
ensureSequenceNumber(securityManager) {
|
|
1162
|
+
if (this.sequenceNumber == undefined) {
|
|
1163
|
+
if (this.isSinglecast()) {
|
|
1164
|
+
this.sequenceNumber = securityManager.nextSequenceNumber(this.nodeId);
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
const groupId = getDestinationIDTX.call(this);
|
|
1168
|
+
this.sequenceNumber = securityManager
|
|
1169
|
+
.nextMulticastSequenceNumber(groupId);
|
|
1170
|
+
}
|
|
1059
1171
|
}
|
|
1060
1172
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1173
|
+
encapsulated;
|
|
1174
|
+
extensions;
|
|
1175
|
+
prepareRetransmission() {
|
|
1176
|
+
super.prepareRetransmission();
|
|
1177
|
+
this.sequenceNumber = undefined;
|
|
1178
|
+
}
|
|
1179
|
+
hasMOSExtension() {
|
|
1180
|
+
return this.extensions.some((e) => e instanceof MOSExtension);
|
|
1181
|
+
}
|
|
1182
|
+
/** Returns the Sender's Entropy Input if this command contains an SPAN extension */
|
|
1183
|
+
getSenderEI() {
|
|
1184
|
+
return getSenderEI(this.extensions);
|
|
1185
|
+
}
|
|
1186
|
+
/** Returns the multicast group ID if this command contains an MGRP extension */
|
|
1187
|
+
getMulticastGroupId() {
|
|
1188
|
+
return getMulticastGroupId(this.extensions);
|
|
1189
|
+
}
|
|
1190
|
+
maybeAddSPANExtension(ctx, securityManager) {
|
|
1191
|
+
if (!this.isSinglecast())
|
|
1192
|
+
return;
|
|
1193
|
+
const receiverNodeId = this.nodeId;
|
|
1194
|
+
const spanState = securityManager.getSPANState(receiverNodeId);
|
|
1195
|
+
if (spanState.type === SPANState.None
|
|
1196
|
+
|| spanState.type === SPANState.LocalEI) {
|
|
1197
|
+
// Can't do anything here if we don't have the receiver's EI
|
|
1198
|
+
throw new ZWaveError(`Security S2 CC requires the receiver's nonce to be sent!`, ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
1199
|
+
}
|
|
1200
|
+
else if (spanState.type === SPANState.RemoteEI) {
|
|
1201
|
+
// We have the receiver's EI, generate our input and send it over
|
|
1202
|
+
// With both, we can create an SPAN
|
|
1203
|
+
const senderEI = securityManager.generateNonce(undefined);
|
|
1204
|
+
const receiverEI = spanState.receiverEI;
|
|
1205
|
+
// While bootstrapping a node, prefer the temporary key, unless the
|
|
1206
|
+
// specific command specifies a security class
|
|
1207
|
+
if (this.securityClass == undefined
|
|
1208
|
+
&& securityManager.tempKeys.has(receiverNodeId)) {
|
|
1209
|
+
securityManager.initializeTempSPAN(receiverNodeId, senderEI, receiverEI);
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
const securityClass = this.securityClass
|
|
1213
|
+
?? ctx.getHighestSecurityClass(receiverNodeId);
|
|
1214
|
+
if (securityClass == undefined) {
|
|
1215
|
+
throw new ZWaveError("No security class defined for this command!", ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
1216
|
+
}
|
|
1217
|
+
securityManager.initializeSPAN(receiverNodeId, securityClass, senderEI, receiverEI);
|
|
1218
|
+
}
|
|
1219
|
+
// Add or update the SPAN extension
|
|
1220
|
+
let spanExtension = this.extensions.find((e) => e instanceof SPANExtension);
|
|
1221
|
+
if (spanExtension) {
|
|
1222
|
+
spanExtension.senderEI = senderEI;
|
|
1223
|
+
}
|
|
1224
|
+
else {
|
|
1225
|
+
spanExtension = new SPANExtension({ senderEI });
|
|
1226
|
+
this.extensions.push(spanExtension);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
serialize(ctx) {
|
|
1231
|
+
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1232
|
+
this.ensureSequenceNumber(securityManager);
|
|
1233
|
+
// Include Sender EI in the command if we only have the receiver's EI
|
|
1234
|
+
this.maybeAddSPANExtension(ctx, securityManager);
|
|
1235
|
+
const unencryptedExtensions = this.extensions.filter((e) => !e.isEncrypted());
|
|
1236
|
+
const encryptedExtensions = this.extensions.filter((e) => e.isEncrypted());
|
|
1237
|
+
const unencryptedPayload = Bytes.concat([
|
|
1238
|
+
Bytes.from([
|
|
1239
|
+
this.sequenceNumber,
|
|
1240
|
+
(encryptedExtensions.length > 0 ? 0b10 : 0)
|
|
1241
|
+
| (unencryptedExtensions.length > 0 ? 1 : 0),
|
|
1242
|
+
]),
|
|
1243
|
+
...unencryptedExtensions.map((e, index) => e.serialize(index < unencryptedExtensions.length - 1)),
|
|
1244
|
+
]);
|
|
1245
|
+
const serializedCC = this.encapsulated?.serialize(ctx)
|
|
1246
|
+
?? new Bytes();
|
|
1247
|
+
const plaintextPayload = Bytes.concat([
|
|
1248
|
+
...encryptedExtensions.map((e, index) => e.serialize(index < encryptedExtensions.length - 1)),
|
|
1249
|
+
serializedCC,
|
|
1250
|
+
]);
|
|
1251
|
+
// Generate the authentication data for CCM encryption
|
|
1252
|
+
const destinationTag = getDestinationIDTX.call(this);
|
|
1253
|
+
const messageLength = this.computeEncapsulationOverhead()
|
|
1254
|
+
+ serializedCC.length;
|
|
1255
|
+
const authData = getAuthenticationData(ctx.ownNodeId, destinationTag, ctx.homeId, messageLength, unencryptedPayload);
|
|
1256
|
+
let key;
|
|
1257
|
+
let iv;
|
|
1097
1258
|
if (this.isSinglecast()) {
|
|
1098
|
-
|
|
1259
|
+
// Singlecast:
|
|
1260
|
+
// Generate a nonce for encryption, and remember it to attempt decryption
|
|
1261
|
+
// of potential in-flight messages from the target node.
|
|
1262
|
+
iv = securityManager.nextNonce(this.nodeId, true);
|
|
1263
|
+
const { keyCCM } =
|
|
1264
|
+
// Prefer the overridden security class if it was given
|
|
1265
|
+
this.securityClass != undefined
|
|
1266
|
+
? securityManager.getKeysForSecurityClass(this.securityClass)
|
|
1267
|
+
: securityManager.getKeysForNode(this.nodeId);
|
|
1268
|
+
key = keyCCM;
|
|
1099
1269
|
}
|
|
1100
1270
|
else {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1271
|
+
// Multicast:
|
|
1272
|
+
const keyAndIV = securityManager.getMulticastKeyAndIV(destinationTag);
|
|
1273
|
+
key = keyAndIV.key;
|
|
1274
|
+
iv = keyAndIV.iv;
|
|
1104
1275
|
}
|
|
1276
|
+
const { ciphertext: ciphertextPayload, authTag } = encryptAES128CCM(key, iv, plaintextPayload, authData, SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1277
|
+
// Remember key and IV for debugging purposes
|
|
1278
|
+
this.key = key;
|
|
1279
|
+
this.iv = iv;
|
|
1280
|
+
this.authData = authData;
|
|
1281
|
+
this.authTag = authTag;
|
|
1282
|
+
this.ciphertext = ciphertextPayload;
|
|
1283
|
+
this.payload = Bytes.concat([
|
|
1284
|
+
unencryptedPayload,
|
|
1285
|
+
ciphertextPayload,
|
|
1286
|
+
authTag,
|
|
1287
|
+
]);
|
|
1288
|
+
return super.serialize(ctx);
|
|
1105
1289
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const spanState = securityManager.getSPANState(receiverNodeId);
|
|
1129
|
-
if (spanState.type === SPANState.None
|
|
1130
|
-
|| spanState.type === SPANState.LocalEI) {
|
|
1131
|
-
// Can't do anything here if we don't have the receiver's EI
|
|
1132
|
-
throw new ZWaveError(`Security S2 CC requires the receiver's nonce to be sent!`, ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
1133
|
-
}
|
|
1134
|
-
else if (spanState.type === SPANState.RemoteEI) {
|
|
1135
|
-
// We have the receiver's EI, generate our input and send it over
|
|
1136
|
-
// With both, we can create an SPAN
|
|
1137
|
-
const senderEI = securityManager.generateNonce(undefined);
|
|
1138
|
-
const receiverEI = spanState.receiverEI;
|
|
1139
|
-
// While bootstrapping a node, prefer the temporary key, unless the
|
|
1140
|
-
// specific command specifies a security class
|
|
1141
|
-
if (this.securityClass == undefined
|
|
1142
|
-
&& securityManager.tempKeys.has(receiverNodeId)) {
|
|
1143
|
-
securityManager.initializeTempSPAN(receiverNodeId, senderEI, receiverEI);
|
|
1290
|
+
computeEncapsulationOverhead() {
|
|
1291
|
+
// Security S2 adds:
|
|
1292
|
+
// * 1 byte sequence number
|
|
1293
|
+
// * 1 byte control
|
|
1294
|
+
// * N bytes extensions
|
|
1295
|
+
// * SECURITY_S2_AUTH_TAG_LENGTH bytes auth tag
|
|
1296
|
+
const extensionBytes = this.extensions
|
|
1297
|
+
.map((e) => e.computeLength())
|
|
1298
|
+
.reduce((a, b) => a + b, 0);
|
|
1299
|
+
return (super.computeEncapsulationOverhead()
|
|
1300
|
+
+ 2
|
|
1301
|
+
+ SECURITY_S2_AUTH_TAG_LENGTH
|
|
1302
|
+
+ extensionBytes);
|
|
1303
|
+
}
|
|
1304
|
+
toLogEntry(ctx) {
|
|
1305
|
+
const message = {
|
|
1306
|
+
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1307
|
+
};
|
|
1308
|
+
if (this.extensions.length > 0) {
|
|
1309
|
+
message.extensions = this.extensions
|
|
1310
|
+
.map((e) => e.toLogEntry())
|
|
1311
|
+
.join("");
|
|
1144
1312
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
if (
|
|
1149
|
-
|
|
1313
|
+
// Log the used keys in integration tests
|
|
1314
|
+
if (process.env.NODE_ENV === "test"
|
|
1315
|
+
|| process.env.NODE_ENV === "development") {
|
|
1316
|
+
if (this.key) {
|
|
1317
|
+
message.key = buffer2hex(this.key);
|
|
1318
|
+
}
|
|
1319
|
+
if (this.iv) {
|
|
1320
|
+
message.IV = buffer2hex(this.iv);
|
|
1321
|
+
}
|
|
1322
|
+
if (this.ciphertext) {
|
|
1323
|
+
message.ciphertext = buffer2hex(this.ciphertext);
|
|
1324
|
+
}
|
|
1325
|
+
else if (this.plaintext) {
|
|
1326
|
+
message.plaintext = buffer2hex(this.plaintext);
|
|
1327
|
+
}
|
|
1328
|
+
if (this.authData) {
|
|
1329
|
+
message["auth data"] = buffer2hex(this.authData);
|
|
1330
|
+
}
|
|
1331
|
+
if (this.authTag) {
|
|
1332
|
+
message["auth tag"] = buffer2hex(this.authTag);
|
|
1150
1333
|
}
|
|
1151
|
-
securityManager.initializeSPAN(receiverNodeId, securityClass, senderEI, receiverEI);
|
|
1152
|
-
}
|
|
1153
|
-
// Add or update the SPAN extension
|
|
1154
|
-
let spanExtension = this.extensions.find((e) => e instanceof SPANExtension);
|
|
1155
|
-
if (spanExtension) {
|
|
1156
|
-
spanExtension.senderEI = senderEI;
|
|
1157
1334
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
this.extensions.push(spanExtension);
|
|
1335
|
+
if (this.securityClass != undefined) {
|
|
1336
|
+
message["security class"] = getEnumMemberName(SecurityClass, this.securityClass);
|
|
1161
1337
|
}
|
|
1338
|
+
return {
|
|
1339
|
+
...super.toLogEntry(ctx),
|
|
1340
|
+
message,
|
|
1341
|
+
};
|
|
1162
1342
|
}
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
])
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
const plaintextPayload = Bytes.concat([
|
|
1182
|
-
...encryptedExtensions.map((e, index) => e.serialize(index < encryptedExtensions.length - 1)),
|
|
1183
|
-
serializedCC,
|
|
1184
|
-
]);
|
|
1185
|
-
// Generate the authentication data for CCM encryption
|
|
1186
|
-
const destinationTag = getDestinationIDTX.call(this);
|
|
1187
|
-
const messageLength = this.computeEncapsulationOverhead()
|
|
1188
|
-
+ serializedCC.length;
|
|
1189
|
-
const authData = getAuthenticationData(ctx.ownNodeId, destinationTag, ctx.homeId, messageLength, unencryptedPayload);
|
|
1190
|
-
let key;
|
|
1191
|
-
let iv;
|
|
1192
|
-
if (this.isSinglecast()) {
|
|
1193
|
-
// Singlecast:
|
|
1194
|
-
// Generate a nonce for encryption, and remember it to attempt decryption
|
|
1195
|
-
// of potential in-flight messages from the target node.
|
|
1196
|
-
iv = securityManager.nextNonce(this.nodeId, true);
|
|
1197
|
-
const { keyCCM } =
|
|
1198
|
-
// Prefer the overridden security class if it was given
|
|
1199
|
-
this.securityClass != undefined
|
|
1200
|
-
? securityManager.getKeysForSecurityClass(this.securityClass)
|
|
1201
|
-
: securityManager.getKeysForNode(this.nodeId);
|
|
1202
|
-
key = keyCCM;
|
|
1343
|
+
};
|
|
1344
|
+
return Security2CCMessageEncapsulation = _classThis;
|
|
1345
|
+
})();
|
|
1346
|
+
export { Security2CCMessageEncapsulation };
|
|
1347
|
+
let Security2CCNonceReport = (() => {
|
|
1348
|
+
let _classDecorators = [CCCommand(Security2Command.NonceReport)];
|
|
1349
|
+
let _classDescriptor;
|
|
1350
|
+
let _classExtraInitializers = [];
|
|
1351
|
+
let _classThis;
|
|
1352
|
+
let _classSuper = Security2CC;
|
|
1353
|
+
var Security2CCNonceReport = class extends _classSuper {
|
|
1354
|
+
static { _classThis = this; }
|
|
1355
|
+
static {
|
|
1356
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1357
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1358
|
+
Security2CCNonceReport = _classThis = _classDescriptor.value;
|
|
1359
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1360
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1203
1361
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
+ SECURITY_S2_AUTH_TAG_LENGTH
|
|
1236
|
-
+ extensionBytes);
|
|
1237
|
-
}
|
|
1238
|
-
toLogEntry(ctx) {
|
|
1239
|
-
const message = {
|
|
1240
|
-
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1241
|
-
};
|
|
1242
|
-
if (this.extensions.length > 0) {
|
|
1243
|
-
message.extensions = this.extensions
|
|
1244
|
-
.map((e) => e.toLogEntry())
|
|
1245
|
-
.join("");
|
|
1246
|
-
}
|
|
1247
|
-
// Log the used keys in integration tests
|
|
1248
|
-
if (process.env.NODE_ENV === "test"
|
|
1249
|
-
|| process.env.NODE_ENV === "development") {
|
|
1250
|
-
if (this.key) {
|
|
1251
|
-
message.key = buffer2hex(this.key);
|
|
1362
|
+
constructor(options) {
|
|
1363
|
+
super(options);
|
|
1364
|
+
this.SOS = options.SOS;
|
|
1365
|
+
this.MOS = options.MOS;
|
|
1366
|
+
this.sequenceNumber = options.sequenceNumber;
|
|
1367
|
+
if (options.SOS)
|
|
1368
|
+
this.receiverEI = options.receiverEI;
|
|
1369
|
+
}
|
|
1370
|
+
static from(raw, ctx) {
|
|
1371
|
+
// Make sure that we can send/receive secure commands
|
|
1372
|
+
const securityManager = assertSecurityRX(ctx);
|
|
1373
|
+
validatePayload(raw.payload.length >= 2);
|
|
1374
|
+
const sequenceNumber = raw.payload[0];
|
|
1375
|
+
// Don't accept duplicate commands
|
|
1376
|
+
validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1377
|
+
const MOS = !!(raw.payload[1] & 0b10);
|
|
1378
|
+
const SOS = !!(raw.payload[1] & 0b1);
|
|
1379
|
+
if (SOS) {
|
|
1380
|
+
// If the SOS flag is set, the REI field MUST be included in the command
|
|
1381
|
+
validatePayload(raw.payload.length >= 18);
|
|
1382
|
+
const receiverEI = raw.payload.subarray(2, 18);
|
|
1383
|
+
// In that case we also need to store it, so the next sent command
|
|
1384
|
+
// can use it for encryption
|
|
1385
|
+
securityManager.storeRemoteEI(ctx.sourceNodeId, receiverEI);
|
|
1386
|
+
return new this({
|
|
1387
|
+
nodeId: ctx.sourceNodeId,
|
|
1388
|
+
sequenceNumber,
|
|
1389
|
+
MOS,
|
|
1390
|
+
SOS,
|
|
1391
|
+
receiverEI,
|
|
1392
|
+
});
|
|
1252
1393
|
}
|
|
1253
|
-
if (
|
|
1254
|
-
|
|
1394
|
+
else if (MOS) {
|
|
1395
|
+
return new this({
|
|
1396
|
+
nodeId: ctx.sourceNodeId,
|
|
1397
|
+
sequenceNumber,
|
|
1398
|
+
MOS,
|
|
1399
|
+
SOS: false,
|
|
1400
|
+
});
|
|
1255
1401
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1402
|
+
else {
|
|
1403
|
+
validatePayload.fail("Either MOS or SOS must be set");
|
|
1258
1404
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1405
|
+
}
|
|
1406
|
+
sequenceNumber;
|
|
1407
|
+
ensureSequenceNumber(securityManager) {
|
|
1408
|
+
if (this.sequenceNumber == undefined) {
|
|
1409
|
+
this.sequenceNumber = securityManager.nextSequenceNumber(this.nodeId);
|
|
1261
1410
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1411
|
+
}
|
|
1412
|
+
SOS;
|
|
1413
|
+
MOS;
|
|
1414
|
+
receiverEI;
|
|
1415
|
+
serialize(ctx) {
|
|
1416
|
+
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1417
|
+
this.ensureSequenceNumber(securityManager);
|
|
1418
|
+
this.payload = Bytes.from([
|
|
1419
|
+
this.sequenceNumber,
|
|
1420
|
+
(this.MOS ? 0b10 : 0) + (this.SOS ? 0b1 : 0),
|
|
1421
|
+
]);
|
|
1422
|
+
if (this.SOS) {
|
|
1423
|
+
this.payload = Bytes.concat([this.payload, this.receiverEI]);
|
|
1264
1424
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1425
|
+
return super.serialize(ctx);
|
|
1426
|
+
}
|
|
1427
|
+
toLogEntry(ctx) {
|
|
1428
|
+
const message = {
|
|
1429
|
+
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1430
|
+
SOS: this.SOS,
|
|
1431
|
+
MOS: this.MOS,
|
|
1432
|
+
};
|
|
1433
|
+
if (this.receiverEI) {
|
|
1434
|
+
message["receiver entropy"] = buffer2hex(this.receiverEI);
|
|
1267
1435
|
}
|
|
1436
|
+
return {
|
|
1437
|
+
...super.toLogEntry(ctx),
|
|
1438
|
+
message,
|
|
1439
|
+
};
|
|
1268
1440
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1441
|
+
};
|
|
1442
|
+
return Security2CCNonceReport = _classThis;
|
|
1443
|
+
})();
|
|
1444
|
+
export { Security2CCNonceReport };
|
|
1445
|
+
let Security2CCNonceGet = (() => {
|
|
1446
|
+
let _classDecorators = [CCCommand(Security2Command.NonceGet), expectedCCResponse(Security2CCNonceReport)];
|
|
1447
|
+
let _classDescriptor;
|
|
1448
|
+
let _classExtraInitializers = [];
|
|
1449
|
+
let _classThis;
|
|
1450
|
+
let _classSuper = Security2CC;
|
|
1451
|
+
var Security2CCNonceGet = class extends _classSuper {
|
|
1452
|
+
static { _classThis = this; }
|
|
1453
|
+
static {
|
|
1454
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1455
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1456
|
+
Security2CCNonceGet = _classThis = _classDescriptor.value;
|
|
1457
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1458
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1271
1459
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
};
|
|
1278
|
-
Security2CCMessageEncapsulation = Security2CCMessageEncapsulation_1 = __decorate([
|
|
1279
|
-
CCCommand(Security2Command.MessageEncapsulation),
|
|
1280
|
-
expectedCCResponse(getCCResponseForMessageEncapsulation, testCCResponseForMessageEncapsulation)
|
|
1281
|
-
], Security2CCMessageEncapsulation);
|
|
1282
|
-
export { Security2CCMessageEncapsulation };
|
|
1283
|
-
let Security2CCNonceReport = Security2CCNonceReport_1 = class Security2CCNonceReport extends Security2CC {
|
|
1284
|
-
constructor(options) {
|
|
1285
|
-
super(options);
|
|
1286
|
-
this.SOS = options.SOS;
|
|
1287
|
-
this.MOS = options.MOS;
|
|
1288
|
-
this.sequenceNumber = options.sequenceNumber;
|
|
1289
|
-
if (options.SOS)
|
|
1290
|
-
this.receiverEI = options.receiverEI;
|
|
1291
|
-
}
|
|
1292
|
-
static from(raw, ctx) {
|
|
1293
|
-
// Make sure that we can send/receive secure commands
|
|
1294
|
-
const securityManager = assertSecurityRX(ctx);
|
|
1295
|
-
validatePayload(raw.payload.length >= 2);
|
|
1296
|
-
const sequenceNumber = raw.payload[0];
|
|
1297
|
-
// Don't accept duplicate commands
|
|
1298
|
-
validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1299
|
-
const MOS = !!(raw.payload[1] & 0b10);
|
|
1300
|
-
const SOS = !!(raw.payload[1] & 0b1);
|
|
1301
|
-
if (SOS) {
|
|
1302
|
-
// If the SOS flag is set, the REI field MUST be included in the command
|
|
1303
|
-
validatePayload(raw.payload.length >= 18);
|
|
1304
|
-
const receiverEI = raw.payload.subarray(2, 18);
|
|
1305
|
-
// In that case we also need to store it, so the next sent command
|
|
1306
|
-
// can use it for encryption
|
|
1307
|
-
securityManager.storeRemoteEI(ctx.sourceNodeId, receiverEI);
|
|
1308
|
-
return new Security2CCNonceReport_1({
|
|
1309
|
-
nodeId: ctx.sourceNodeId,
|
|
1310
|
-
sequenceNumber,
|
|
1311
|
-
MOS,
|
|
1312
|
-
SOS,
|
|
1313
|
-
receiverEI,
|
|
1314
|
-
});
|
|
1460
|
+
// TODO: A node sending this command MUST accept a delay up to <Previous Round-trip-time to peer node> +
|
|
1461
|
+
// 250 ms before receiving the Security 2 Nonce Report Command.
|
|
1462
|
+
constructor(options) {
|
|
1463
|
+
super(options);
|
|
1464
|
+
this.sequenceNumber = options.sequenceNumber;
|
|
1315
1465
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1466
|
+
static from(raw, ctx) {
|
|
1467
|
+
const securityManager = assertSecurityRX(ctx);
|
|
1468
|
+
validatePayload(raw.payload.length >= 1);
|
|
1469
|
+
const sequenceNumber = raw.payload[0];
|
|
1470
|
+
// Don't accept duplicate commands
|
|
1471
|
+
validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1472
|
+
return new this({
|
|
1318
1473
|
nodeId: ctx.sourceNodeId,
|
|
1319
1474
|
sequenceNumber,
|
|
1320
|
-
MOS,
|
|
1321
|
-
SOS: false,
|
|
1322
1475
|
});
|
|
1323
1476
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
ensureSequenceNumber(securityManager) {
|
|
1330
|
-
if (this.sequenceNumber == undefined) {
|
|
1331
|
-
this.sequenceNumber = securityManager.nextSequenceNumber(this.nodeId);
|
|
1477
|
+
sequenceNumber;
|
|
1478
|
+
ensureSequenceNumber(securityManager) {
|
|
1479
|
+
if (this.sequenceNumber == undefined) {
|
|
1480
|
+
this.sequenceNumber = securityManager.nextSequenceNumber(this.nodeId);
|
|
1481
|
+
}
|
|
1332
1482
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1339
|
-
this.ensureSequenceNumber(securityManager);
|
|
1340
|
-
this.payload = Bytes.from([
|
|
1341
|
-
this.sequenceNumber,
|
|
1342
|
-
(this.MOS ? 0b10 : 0) + (this.SOS ? 0b1 : 0),
|
|
1343
|
-
]);
|
|
1344
|
-
if (this.SOS) {
|
|
1345
|
-
this.payload = Bytes.concat([this.payload, this.receiverEI]);
|
|
1346
|
-
}
|
|
1347
|
-
return super.serialize(ctx);
|
|
1348
|
-
}
|
|
1349
|
-
toLogEntry(ctx) {
|
|
1350
|
-
const message = {
|
|
1351
|
-
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1352
|
-
SOS: this.SOS,
|
|
1353
|
-
MOS: this.MOS,
|
|
1354
|
-
};
|
|
1355
|
-
if (this.receiverEI) {
|
|
1356
|
-
message["receiver entropy"] = buffer2hex(this.receiverEI);
|
|
1483
|
+
serialize(ctx) {
|
|
1484
|
+
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1485
|
+
this.ensureSequenceNumber(securityManager);
|
|
1486
|
+
this.payload = Bytes.from([this.sequenceNumber]);
|
|
1487
|
+
return super.serialize(ctx);
|
|
1357
1488
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
CCCommand(Security2Command.NonceReport)
|
|
1366
|
-
], Security2CCNonceReport);
|
|
1367
|
-
export { Security2CCNonceReport };
|
|
1368
|
-
let Security2CCNonceGet = Security2CCNonceGet_1 = class Security2CCNonceGet extends Security2CC {
|
|
1369
|
-
// TODO: A node sending this command MUST accept a delay up to <Previous Round-trip-time to peer node> +
|
|
1370
|
-
// 250 ms before receiving the Security 2 Nonce Report Command.
|
|
1371
|
-
constructor(options) {
|
|
1372
|
-
super(options);
|
|
1373
|
-
this.sequenceNumber = options.sequenceNumber;
|
|
1374
|
-
}
|
|
1375
|
-
static from(raw, ctx) {
|
|
1376
|
-
const securityManager = assertSecurityRX(ctx);
|
|
1377
|
-
validatePayload(raw.payload.length >= 1);
|
|
1378
|
-
const sequenceNumber = raw.payload[0];
|
|
1379
|
-
// Don't accept duplicate commands
|
|
1380
|
-
validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1381
|
-
return new Security2CCNonceGet_1({
|
|
1382
|
-
nodeId: ctx.sourceNodeId,
|
|
1383
|
-
sequenceNumber,
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
sequenceNumber;
|
|
1387
|
-
ensureSequenceNumber(securityManager) {
|
|
1388
|
-
if (this.sequenceNumber == undefined) {
|
|
1389
|
-
this.sequenceNumber = securityManager.nextSequenceNumber(this.nodeId);
|
|
1489
|
+
toLogEntry(ctx) {
|
|
1490
|
+
return {
|
|
1491
|
+
...super.toLogEntry(ctx),
|
|
1492
|
+
message: {
|
|
1493
|
+
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1494
|
+
},
|
|
1495
|
+
};
|
|
1390
1496
|
}
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
this.ensureSequenceNumber(securityManager);
|
|
1395
|
-
this.payload = Bytes.from([this.sequenceNumber]);
|
|
1396
|
-
return super.serialize(ctx);
|
|
1397
|
-
}
|
|
1398
|
-
toLogEntry(ctx) {
|
|
1399
|
-
return {
|
|
1400
|
-
...super.toLogEntry(ctx),
|
|
1401
|
-
message: {
|
|
1402
|
-
"sequence number": this.sequenceNumber ?? "(not set)",
|
|
1403
|
-
},
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
};
|
|
1407
|
-
Security2CCNonceGet = Security2CCNonceGet_1 = __decorate([
|
|
1408
|
-
CCCommand(Security2Command.NonceGet),
|
|
1409
|
-
expectedCCResponse(Security2CCNonceReport)
|
|
1410
|
-
], Security2CCNonceGet);
|
|
1497
|
+
};
|
|
1498
|
+
return Security2CCNonceGet = _classThis;
|
|
1499
|
+
})();
|
|
1411
1500
|
export { Security2CCNonceGet };
|
|
1412
|
-
let Security2CCKEXReport =
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
_reserved;
|
|
1443
|
-
requestCSA;
|
|
1444
|
-
echo;
|
|
1445
|
-
supportedKEXSchemes;
|
|
1446
|
-
supportedECDHProfiles;
|
|
1447
|
-
requestedKeys;
|
|
1448
|
-
serialize(ctx) {
|
|
1449
|
-
this.payload = Bytes.concat([
|
|
1450
|
-
Bytes.from([
|
|
1451
|
-
this._reserved
|
|
1452
|
-
+ (this.requestCSA ? 0b10 : 0)
|
|
1453
|
-
+ (this.echo ? 0b1 : 0),
|
|
1454
|
-
]),
|
|
1501
|
+
let Security2CCKEXReport = (() => {
|
|
1502
|
+
let _classDecorators = [CCCommand(Security2Command.KEXReport)];
|
|
1503
|
+
let _classDescriptor;
|
|
1504
|
+
let _classExtraInitializers = [];
|
|
1505
|
+
let _classThis;
|
|
1506
|
+
let _classSuper = Security2CC;
|
|
1507
|
+
var Security2CCKEXReport = class extends _classSuper {
|
|
1508
|
+
static { _classThis = this; }
|
|
1509
|
+
static {
|
|
1510
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1511
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1512
|
+
Security2CCKEXReport = _classThis = _classDescriptor.value;
|
|
1513
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1514
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1515
|
+
}
|
|
1516
|
+
constructor(options) {
|
|
1517
|
+
super(options);
|
|
1518
|
+
this.requestCSA = options.requestCSA;
|
|
1519
|
+
this.echo = options.echo;
|
|
1520
|
+
this._reserved = options._reserved ?? 0;
|
|
1521
|
+
this.supportedKEXSchemes = options.supportedKEXSchemes;
|
|
1522
|
+
this.supportedECDHProfiles = options.supportedECDHProfiles;
|
|
1523
|
+
this.requestedKeys = options.requestedKeys;
|
|
1524
|
+
}
|
|
1525
|
+
static from(raw, ctx) {
|
|
1526
|
+
validatePayload(raw.payload.length >= 4);
|
|
1527
|
+
const requestCSA = !!(raw.payload[0] & 0b10);
|
|
1528
|
+
const echo = !!(raw.payload[0] & 0b1);
|
|
1529
|
+
// Remember the reserved bits for the echo
|
|
1530
|
+
const _reserved = raw.payload[0] & 0b1111_1100;
|
|
1455
1531
|
// The bit mask starts at 0, but bit 0 is not used
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1532
|
+
const supportedKEXSchemes = parseBitMask(raw.payload.subarray(1, 2), 0).filter((s) => s !== 0);
|
|
1533
|
+
const supportedECDHProfiles = parseBitMask(raw.payload.subarray(2, 3), ECDHProfiles.Curve25519);
|
|
1534
|
+
const requestedKeys = parseBitMask(raw.payload.subarray(3, 4), SecurityClass.S2_Unauthenticated);
|
|
1535
|
+
return new this({
|
|
1536
|
+
nodeId: ctx.sourceNodeId,
|
|
1537
|
+
requestCSA,
|
|
1538
|
+
echo,
|
|
1539
|
+
_reserved,
|
|
1540
|
+
supportedKEXSchemes,
|
|
1541
|
+
supportedECDHProfiles,
|
|
1542
|
+
requestedKeys,
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
_reserved;
|
|
1546
|
+
requestCSA;
|
|
1547
|
+
echo;
|
|
1548
|
+
supportedKEXSchemes;
|
|
1549
|
+
supportedECDHProfiles;
|
|
1550
|
+
requestedKeys;
|
|
1551
|
+
serialize(ctx) {
|
|
1552
|
+
this.payload = Bytes.concat([
|
|
1553
|
+
Bytes.from([
|
|
1554
|
+
this._reserved
|
|
1555
|
+
+ (this.requestCSA ? 0b10 : 0)
|
|
1556
|
+
+ (this.echo ? 0b1 : 0),
|
|
1557
|
+
]),
|
|
1558
|
+
// The bit mask starts at 0, but bit 0 is not used
|
|
1559
|
+
encodeBitMask(this.supportedKEXSchemes, 7, 0),
|
|
1560
|
+
encodeBitMask(this.supportedECDHProfiles, 7, ECDHProfiles.Curve25519),
|
|
1561
|
+
encodeBitMask(this.requestedKeys, SecurityClass.S0_Legacy, SecurityClass.S2_Unauthenticated),
|
|
1562
|
+
]);
|
|
1563
|
+
return super.serialize(ctx);
|
|
1564
|
+
}
|
|
1565
|
+
toLogEntry(ctx) {
|
|
1566
|
+
return {
|
|
1567
|
+
...super.toLogEntry(ctx),
|
|
1568
|
+
message: {
|
|
1569
|
+
echo: this.echo,
|
|
1570
|
+
"supported schemes": this.supportedKEXSchemes
|
|
1571
|
+
.map((s) => `\n· ${getEnumMemberName(KEXSchemes, s)}`)
|
|
1572
|
+
.join(""),
|
|
1573
|
+
"supported ECDH profiles": this.supportedECDHProfiles
|
|
1574
|
+
.map((s) => `\n· ${getEnumMemberName(ECDHProfiles, s)}`)
|
|
1575
|
+
.join(""),
|
|
1576
|
+
"CSA requested": this.requestCSA,
|
|
1577
|
+
"requested security classes": this.requestedKeys
|
|
1578
|
+
.map((s) => `\n· ${getEnumMemberName(SecurityClass, s)}`)
|
|
1579
|
+
.join(""),
|
|
1580
|
+
},
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
return Security2CCKEXReport = _classThis;
|
|
1585
|
+
})();
|
|
1484
1586
|
export { Security2CCKEXReport };
|
|
1485
|
-
let Security2CCKEXGet =
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1587
|
+
let Security2CCKEXGet = (() => {
|
|
1588
|
+
let _classDecorators = [CCCommand(Security2Command.KEXGet), expectedCCResponse(Security2CCKEXReport)];
|
|
1589
|
+
let _classDescriptor;
|
|
1590
|
+
let _classExtraInitializers = [];
|
|
1591
|
+
let _classThis;
|
|
1592
|
+
let _classSuper = Security2CC;
|
|
1593
|
+
var Security2CCKEXGet = class extends _classSuper {
|
|
1594
|
+
static { _classThis = this; }
|
|
1595
|
+
static {
|
|
1596
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1597
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1598
|
+
Security2CCKEXGet = _classThis = _classDescriptor.value;
|
|
1599
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1600
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
return Security2CCKEXGet = _classThis;
|
|
1604
|
+
})();
|
|
1491
1605
|
export { Security2CCKEXGet };
|
|
1492
1606
|
function getExpectedResponseForKEXSet(sent) {
|
|
1493
1607
|
if (sent.echo) {
|
|
@@ -1508,307 +1622,420 @@ function testExpectedResponseForKEXSet(sent, received) {
|
|
|
1508
1622
|
}
|
|
1509
1623
|
return false;
|
|
1510
1624
|
}
|
|
1511
|
-
let Security2CCKEXSet =
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
selectedECDHProfile,
|
|
1541
|
-
grantedKeys,
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
_reserved;
|
|
1545
|
-
permitCSA;
|
|
1546
|
-
echo;
|
|
1547
|
-
selectedKEXScheme;
|
|
1548
|
-
selectedECDHProfile;
|
|
1549
|
-
grantedKeys;
|
|
1550
|
-
serialize(ctx) {
|
|
1551
|
-
this.payload = Bytes.concat([
|
|
1552
|
-
Bytes.from([
|
|
1553
|
-
this._reserved
|
|
1554
|
-
+ (this.permitCSA ? 0b10 : 0)
|
|
1555
|
-
+ (this.echo ? 0b1 : 0),
|
|
1556
|
-
]),
|
|
1625
|
+
let Security2CCKEXSet = (() => {
|
|
1626
|
+
let _classDecorators = [CCCommand(Security2Command.KEXSet), expectedCCResponse(getExpectedResponseForKEXSet, testExpectedResponseForKEXSet)];
|
|
1627
|
+
let _classDescriptor;
|
|
1628
|
+
let _classExtraInitializers = [];
|
|
1629
|
+
let _classThis;
|
|
1630
|
+
let _classSuper = Security2CC;
|
|
1631
|
+
var Security2CCKEXSet = class extends _classSuper {
|
|
1632
|
+
static { _classThis = this; }
|
|
1633
|
+
static {
|
|
1634
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1635
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1636
|
+
Security2CCKEXSet = _classThis = _classDescriptor.value;
|
|
1637
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1638
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1639
|
+
}
|
|
1640
|
+
constructor(options) {
|
|
1641
|
+
super(options);
|
|
1642
|
+
this.permitCSA = options.permitCSA;
|
|
1643
|
+
this.echo = options.echo;
|
|
1644
|
+
this._reserved = options._reserved ?? 0;
|
|
1645
|
+
this.selectedKEXScheme = options.selectedKEXScheme;
|
|
1646
|
+
this.selectedECDHProfile = options.selectedECDHProfile;
|
|
1647
|
+
this.grantedKeys = options.grantedKeys;
|
|
1648
|
+
}
|
|
1649
|
+
static from(raw, ctx) {
|
|
1650
|
+
validatePayload(raw.payload.length >= 4);
|
|
1651
|
+
const _reserved = raw.payload[0] & 0b1111_1100;
|
|
1652
|
+
const permitCSA = !!(raw.payload[0] & 0b10);
|
|
1653
|
+
const echo = !!(raw.payload[0] & 0b1);
|
|
1557
1654
|
// The bit mask starts at 0, but bit 0 is not used
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1655
|
+
const selectedKEXSchemes = parseBitMask(raw.payload.subarray(1, 2), 0).filter((s) => s !== 0);
|
|
1656
|
+
validatePayload(selectedKEXSchemes.length === 1);
|
|
1657
|
+
const selectedKEXScheme = selectedKEXSchemes[0];
|
|
1658
|
+
const selectedECDHProfiles = parseBitMask(raw.payload.subarray(2, 3), ECDHProfiles.Curve25519);
|
|
1659
|
+
validatePayload(selectedECDHProfiles.length === 1);
|
|
1660
|
+
const selectedECDHProfile = selectedECDHProfiles[0];
|
|
1661
|
+
const grantedKeys = parseBitMask(raw.payload.subarray(3, 4), SecurityClass.S2_Unauthenticated);
|
|
1662
|
+
return new this({
|
|
1663
|
+
nodeId: ctx.sourceNodeId,
|
|
1664
|
+
_reserved,
|
|
1665
|
+
permitCSA,
|
|
1666
|
+
echo,
|
|
1667
|
+
selectedKEXScheme,
|
|
1668
|
+
selectedECDHProfile,
|
|
1669
|
+
grantedKeys,
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
_reserved;
|
|
1673
|
+
permitCSA;
|
|
1674
|
+
echo;
|
|
1675
|
+
selectedKEXScheme;
|
|
1676
|
+
selectedECDHProfile;
|
|
1677
|
+
grantedKeys;
|
|
1678
|
+
serialize(ctx) {
|
|
1679
|
+
this.payload = Bytes.concat([
|
|
1680
|
+
Bytes.from([
|
|
1681
|
+
this._reserved
|
|
1682
|
+
+ (this.permitCSA ? 0b10 : 0)
|
|
1683
|
+
+ (this.echo ? 0b1 : 0),
|
|
1684
|
+
]),
|
|
1685
|
+
// The bit mask starts at 0, but bit 0 is not used
|
|
1686
|
+
encodeBitMask([this.selectedKEXScheme], 7, 0),
|
|
1687
|
+
encodeBitMask([this.selectedECDHProfile], 7, ECDHProfiles.Curve25519),
|
|
1688
|
+
encodeBitMask(this.grantedKeys, SecurityClass.S0_Legacy, SecurityClass.S2_Unauthenticated),
|
|
1689
|
+
]);
|
|
1690
|
+
return super.serialize(ctx);
|
|
1691
|
+
}
|
|
1692
|
+
toLogEntry(ctx) {
|
|
1693
|
+
return {
|
|
1694
|
+
...super.toLogEntry(ctx),
|
|
1695
|
+
message: {
|
|
1696
|
+
echo: this.echo,
|
|
1697
|
+
"selected scheme": getEnumMemberName(KEXSchemes, this.selectedKEXScheme),
|
|
1698
|
+
"selected ECDH profile": getEnumMemberName(ECDHProfiles, this.selectedECDHProfile),
|
|
1699
|
+
"CSA permitted": this.permitCSA,
|
|
1700
|
+
"granted security classes": this.grantedKeys
|
|
1701
|
+
.map((s) => `\n· ${getEnumMemberName(SecurityClass, s)}`)
|
|
1702
|
+
.join(""),
|
|
1703
|
+
},
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
return Security2CCKEXSet = _classThis;
|
|
1708
|
+
})();
|
|
1583
1709
|
export { Security2CCKEXSet };
|
|
1584
|
-
let Security2CCKEXFail =
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1710
|
+
let Security2CCKEXFail = (() => {
|
|
1711
|
+
let _classDecorators = [CCCommand(Security2Command.KEXFail)];
|
|
1712
|
+
let _classDescriptor;
|
|
1713
|
+
let _classExtraInitializers = [];
|
|
1714
|
+
let _classThis;
|
|
1715
|
+
let _classSuper = Security2CC;
|
|
1716
|
+
var Security2CCKEXFail = class extends _classSuper {
|
|
1717
|
+
static { _classThis = this; }
|
|
1718
|
+
static {
|
|
1719
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1720
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1721
|
+
Security2CCKEXFail = _classThis = _classDescriptor.value;
|
|
1722
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1723
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1724
|
+
}
|
|
1725
|
+
constructor(options) {
|
|
1726
|
+
super(options);
|
|
1727
|
+
this.failType = options.failType;
|
|
1728
|
+
}
|
|
1729
|
+
static from(raw, ctx) {
|
|
1730
|
+
validatePayload(raw.payload.length >= 1);
|
|
1731
|
+
const failType = raw.payload[0];
|
|
1732
|
+
return new this({
|
|
1733
|
+
nodeId: ctx.sourceNodeId,
|
|
1734
|
+
failType,
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
failType;
|
|
1738
|
+
serialize(ctx) {
|
|
1739
|
+
this.payload = Bytes.from([this.failType]);
|
|
1740
|
+
return super.serialize(ctx);
|
|
1741
|
+
}
|
|
1742
|
+
toLogEntry(ctx) {
|
|
1743
|
+
return {
|
|
1744
|
+
...super.toLogEntry(ctx),
|
|
1745
|
+
message: { reason: getEnumMemberName(KEXFailType, this.failType) },
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
return Security2CCKEXFail = _classThis;
|
|
1750
|
+
})();
|
|
1612
1751
|
export { Security2CCKEXFail };
|
|
1613
|
-
let Security2CCPublicKeyReport =
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1752
|
+
let Security2CCPublicKeyReport = (() => {
|
|
1753
|
+
let _classDecorators = [CCCommand(Security2Command.PublicKeyReport)];
|
|
1754
|
+
let _classDescriptor;
|
|
1755
|
+
let _classExtraInitializers = [];
|
|
1756
|
+
let _classThis;
|
|
1757
|
+
let _classSuper = Security2CC;
|
|
1758
|
+
var Security2CCPublicKeyReport = class extends _classSuper {
|
|
1759
|
+
static { _classThis = this; }
|
|
1760
|
+
static {
|
|
1761
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1762
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1763
|
+
Security2CCPublicKeyReport = _classThis = _classDescriptor.value;
|
|
1764
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1765
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1766
|
+
}
|
|
1767
|
+
constructor(options) {
|
|
1768
|
+
super(options);
|
|
1769
|
+
this.includingNode = options.includingNode;
|
|
1770
|
+
this.publicKey = options.publicKey;
|
|
1771
|
+
}
|
|
1772
|
+
static from(raw, ctx) {
|
|
1773
|
+
validatePayload(raw.payload.length >= 17);
|
|
1774
|
+
const includingNode = !!(raw.payload[0] & 0b1);
|
|
1775
|
+
const publicKey = raw.payload.subarray(1);
|
|
1776
|
+
return new this({
|
|
1777
|
+
nodeId: ctx.sourceNodeId,
|
|
1778
|
+
includingNode,
|
|
1779
|
+
publicKey,
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
includingNode;
|
|
1783
|
+
publicKey;
|
|
1784
|
+
serialize(ctx) {
|
|
1785
|
+
this.payload = Bytes.concat([
|
|
1786
|
+
Bytes.from([this.includingNode ? 1 : 0]),
|
|
1787
|
+
this.publicKey,
|
|
1788
|
+
]);
|
|
1789
|
+
return super.serialize(ctx);
|
|
1790
|
+
}
|
|
1791
|
+
toLogEntry(ctx) {
|
|
1792
|
+
return {
|
|
1793
|
+
...super.toLogEntry(ctx),
|
|
1794
|
+
message: {
|
|
1795
|
+
"is including node": this.includingNode,
|
|
1796
|
+
"public key": buffer2hex(this.publicKey),
|
|
1797
|
+
},
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
return Security2CCPublicKeyReport = _classThis;
|
|
1802
|
+
})();
|
|
1651
1803
|
export { Security2CCPublicKeyReport };
|
|
1652
|
-
let Security2CCNetworkKeyReport =
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1804
|
+
let Security2CCNetworkKeyReport = (() => {
|
|
1805
|
+
let _classDecorators = [CCCommand(Security2Command.NetworkKeyReport)];
|
|
1806
|
+
let _classDescriptor;
|
|
1807
|
+
let _classExtraInitializers = [];
|
|
1808
|
+
let _classThis;
|
|
1809
|
+
let _classSuper = Security2CC;
|
|
1810
|
+
var Security2CCNetworkKeyReport = class extends _classSuper {
|
|
1811
|
+
static { _classThis = this; }
|
|
1812
|
+
static {
|
|
1813
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1814
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1815
|
+
Security2CCNetworkKeyReport = _classThis = _classDescriptor.value;
|
|
1816
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1817
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1818
|
+
}
|
|
1819
|
+
constructor(options) {
|
|
1820
|
+
super(options);
|
|
1821
|
+
this.grantedKey = options.grantedKey;
|
|
1822
|
+
this.networkKey = options.networkKey;
|
|
1823
|
+
}
|
|
1824
|
+
static from(raw, ctx) {
|
|
1825
|
+
validatePayload(raw.payload.length >= 17);
|
|
1826
|
+
const grantedKey = bitMaskToSecurityClass(raw.payload, 0);
|
|
1827
|
+
const networkKey = raw.payload.subarray(1, 17);
|
|
1828
|
+
return new this({
|
|
1829
|
+
nodeId: ctx.sourceNodeId,
|
|
1830
|
+
grantedKey,
|
|
1831
|
+
networkKey,
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
grantedKey;
|
|
1835
|
+
networkKey;
|
|
1836
|
+
serialize(ctx) {
|
|
1837
|
+
this.payload = Bytes.concat([
|
|
1838
|
+
securityClassToBitMask(this.grantedKey),
|
|
1839
|
+
this.networkKey,
|
|
1840
|
+
]);
|
|
1841
|
+
return super.serialize(ctx);
|
|
1842
|
+
}
|
|
1843
|
+
toLogEntry(ctx) {
|
|
1844
|
+
return {
|
|
1845
|
+
...super.toLogEntry(ctx),
|
|
1846
|
+
message: {
|
|
1847
|
+
"security class": getEnumMemberName(SecurityClass, this.grantedKey),
|
|
1848
|
+
// This shouldn't be logged, so users can safely post their logs online
|
|
1849
|
+
// "network key": buffer2hex(this.networkKey),
|
|
1850
|
+
},
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
return Security2CCNetworkKeyReport = _classThis;
|
|
1855
|
+
})();
|
|
1691
1856
|
export { Security2CCNetworkKeyReport };
|
|
1692
|
-
let Security2CCNetworkKeyGet =
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1857
|
+
let Security2CCNetworkKeyGet = (() => {
|
|
1858
|
+
let _classDecorators = [CCCommand(Security2Command.NetworkKeyGet)];
|
|
1859
|
+
let _classDescriptor;
|
|
1860
|
+
let _classExtraInitializers = [];
|
|
1861
|
+
let _classThis;
|
|
1862
|
+
let _classSuper = Security2CC;
|
|
1863
|
+
var Security2CCNetworkKeyGet = class extends _classSuper {
|
|
1864
|
+
static { _classThis = this; }
|
|
1865
|
+
static {
|
|
1866
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1867
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1868
|
+
Security2CCNetworkKeyGet = _classThis = _classDescriptor.value;
|
|
1869
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1870
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1871
|
+
}
|
|
1872
|
+
constructor(options) {
|
|
1873
|
+
super(options);
|
|
1874
|
+
this.requestedKey = options.requestedKey;
|
|
1875
|
+
}
|
|
1876
|
+
static from(raw, ctx) {
|
|
1877
|
+
validatePayload(raw.payload.length >= 1);
|
|
1878
|
+
const requestedKey = bitMaskToSecurityClass(raw.payload, 0);
|
|
1879
|
+
return new this({
|
|
1880
|
+
nodeId: ctx.sourceNodeId,
|
|
1881
|
+
requestedKey,
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
requestedKey;
|
|
1885
|
+
serialize(ctx) {
|
|
1886
|
+
this.payload = securityClassToBitMask(this.requestedKey);
|
|
1887
|
+
return super.serialize(ctx);
|
|
1888
|
+
}
|
|
1889
|
+
toLogEntry(ctx) {
|
|
1890
|
+
return {
|
|
1891
|
+
...super.toLogEntry(ctx),
|
|
1892
|
+
message: {
|
|
1893
|
+
"security class": getEnumMemberName(SecurityClass, this.requestedKey),
|
|
1894
|
+
},
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
return Security2CCNetworkKeyGet = _classThis;
|
|
1899
|
+
})();
|
|
1724
1900
|
export { Security2CCNetworkKeyGet };
|
|
1725
|
-
let Security2CCNetworkKeyVerify =
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1901
|
+
let Security2CCNetworkKeyVerify = (() => {
|
|
1902
|
+
let _classDecorators = [CCCommand(Security2Command.NetworkKeyVerify)];
|
|
1903
|
+
let _classDescriptor;
|
|
1904
|
+
let _classExtraInitializers = [];
|
|
1905
|
+
let _classThis;
|
|
1906
|
+
let _classSuper = Security2CC;
|
|
1907
|
+
var Security2CCNetworkKeyVerify = class extends _classSuper {
|
|
1908
|
+
static { _classThis = this; }
|
|
1909
|
+
static {
|
|
1910
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1911
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1912
|
+
Security2CCNetworkKeyVerify = _classThis = _classDescriptor.value;
|
|
1913
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1914
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
return Security2CCNetworkKeyVerify = _classThis;
|
|
1918
|
+
})();
|
|
1730
1919
|
export { Security2CCNetworkKeyVerify };
|
|
1731
|
-
let Security2CCTransferEnd =
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1920
|
+
let Security2CCTransferEnd = (() => {
|
|
1921
|
+
let _classDecorators = [CCCommand(Security2Command.TransferEnd)];
|
|
1922
|
+
let _classDescriptor;
|
|
1923
|
+
let _classExtraInitializers = [];
|
|
1924
|
+
let _classThis;
|
|
1925
|
+
let _classSuper = Security2CC;
|
|
1926
|
+
var Security2CCTransferEnd = class extends _classSuper {
|
|
1927
|
+
static { _classThis = this; }
|
|
1928
|
+
static {
|
|
1929
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1930
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1931
|
+
Security2CCTransferEnd = _classThis = _classDescriptor.value;
|
|
1932
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1933
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1934
|
+
}
|
|
1935
|
+
constructor(options) {
|
|
1936
|
+
super(options);
|
|
1937
|
+
this.keyVerified = options.keyVerified;
|
|
1938
|
+
this.keyRequestComplete = options.keyRequestComplete;
|
|
1939
|
+
}
|
|
1940
|
+
static from(raw, ctx) {
|
|
1941
|
+
validatePayload(raw.payload.length >= 1);
|
|
1942
|
+
const keyVerified = !!(raw.payload[0] & 0b10);
|
|
1943
|
+
const keyRequestComplete = !!(raw.payload[0] & 0b1);
|
|
1944
|
+
return new this({
|
|
1945
|
+
nodeId: ctx.sourceNodeId,
|
|
1946
|
+
keyVerified,
|
|
1947
|
+
keyRequestComplete,
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
keyVerified;
|
|
1951
|
+
keyRequestComplete;
|
|
1952
|
+
serialize(ctx) {
|
|
1953
|
+
this.payload = Bytes.from([
|
|
1954
|
+
(this.keyVerified ? 0b10 : 0) + (this.keyRequestComplete ? 0b1 : 0),
|
|
1955
|
+
]);
|
|
1956
|
+
return super.serialize(ctx);
|
|
1957
|
+
}
|
|
1958
|
+
toLogEntry(ctx) {
|
|
1959
|
+
return {
|
|
1960
|
+
...super.toLogEntry(ctx),
|
|
1961
|
+
message: {
|
|
1962
|
+
"key verified": this.keyVerified,
|
|
1963
|
+
"request complete": this.keyRequestComplete,
|
|
1964
|
+
},
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
};
|
|
1968
|
+
return Security2CCTransferEnd = _classThis;
|
|
1969
|
+
})();
|
|
1768
1970
|
export { Security2CCTransferEnd };
|
|
1769
|
-
let Security2CCCommandsSupportedReport =
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1971
|
+
let Security2CCCommandsSupportedReport = (() => {
|
|
1972
|
+
let _classDecorators = [CCCommand(Security2Command.CommandsSupportedReport)];
|
|
1973
|
+
let _classDescriptor;
|
|
1974
|
+
let _classExtraInitializers = [];
|
|
1975
|
+
let _classThis;
|
|
1976
|
+
let _classSuper = Security2CC;
|
|
1977
|
+
var Security2CCCommandsSupportedReport = class extends _classSuper {
|
|
1978
|
+
static { _classThis = this; }
|
|
1979
|
+
static {
|
|
1980
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1981
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
1982
|
+
Security2CCCommandsSupportedReport = _classThis = _classDescriptor.value;
|
|
1983
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1984
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
1985
|
+
}
|
|
1986
|
+
constructor(options) {
|
|
1987
|
+
super(options);
|
|
1988
|
+
this.supportedCCs = options.supportedCCs;
|
|
1989
|
+
}
|
|
1990
|
+
static from(raw, ctx) {
|
|
1991
|
+
const CCs = parseCCList(raw.payload);
|
|
1992
|
+
// SDS13783: A sending node MAY terminate the list of supported command classes with the
|
|
1993
|
+
// COMMAND_CLASS_MARK command class identifier.
|
|
1994
|
+
// A receiving node MUST stop parsing the list of supported command classes if it detects the
|
|
1995
|
+
// COMMAND_CLASS_MARK command class identifier in the Security 2 Commands Supported Report
|
|
1996
|
+
const supportedCCs = CCs.supportedCCs;
|
|
1997
|
+
return new this({
|
|
1998
|
+
nodeId: ctx.sourceNodeId,
|
|
1999
|
+
supportedCCs,
|
|
2000
|
+
});
|
|
2001
|
+
}
|
|
2002
|
+
supportedCCs;
|
|
2003
|
+
serialize(ctx) {
|
|
2004
|
+
this.payload = encodeCCList(this.supportedCCs, []);
|
|
2005
|
+
return super.serialize(ctx);
|
|
2006
|
+
}
|
|
2007
|
+
toLogEntry(ctx) {
|
|
2008
|
+
return {
|
|
2009
|
+
...super.toLogEntry(ctx),
|
|
2010
|
+
message: {
|
|
2011
|
+
"supported CCs": this.supportedCCs
|
|
2012
|
+
.map((cc) => getCCName(cc))
|
|
2013
|
+
.map((cc) => `\n· ${cc}`)
|
|
2014
|
+
.join(""),
|
|
2015
|
+
},
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
};
|
|
2019
|
+
return Security2CCCommandsSupportedReport = _classThis;
|
|
2020
|
+
})();
|
|
1806
2021
|
export { Security2CCCommandsSupportedReport };
|
|
1807
|
-
let Security2CCCommandsSupportedGet =
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2022
|
+
let Security2CCCommandsSupportedGet = (() => {
|
|
2023
|
+
let _classDecorators = [CCCommand(Security2Command.CommandsSupportedGet), expectedCCResponse(Security2CCCommandsSupportedReport)];
|
|
2024
|
+
let _classDescriptor;
|
|
2025
|
+
let _classExtraInitializers = [];
|
|
2026
|
+
let _classThis;
|
|
2027
|
+
let _classSuper = Security2CC;
|
|
2028
|
+
var Security2CCCommandsSupportedGet = class extends _classSuper {
|
|
2029
|
+
static { _classThis = this; }
|
|
2030
|
+
static {
|
|
2031
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
2032
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
2033
|
+
Security2CCCommandsSupportedGet = _classThis = _classDescriptor.value;
|
|
2034
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
2035
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
2036
|
+
}
|
|
2037
|
+
};
|
|
2038
|
+
return Security2CCCommandsSupportedGet = _classThis;
|
|
2039
|
+
})();
|
|
1813
2040
|
export { Security2CCCommandsSupportedGet };
|
|
1814
2041
|
//# sourceMappingURL=Security2CC.js.map
|