UNPKG

zwave-js

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

128 lines 5.64 kB
import { CommandClass, SecurityCC, SecurityCCCommandEncapsulation, SecurityCCCommandsSupportedGet, SecurityCCCommandsSupportedReport, SecurityCCNetworkKeySet, SecurityCCNetworkKeyVerify, SecurityCCNonceGet, SecurityCCNonceReport, SecurityCCSchemeGet, SecurityCCSchemeReport, } from "@zwave-js/cc"; import { CommandClasses, SecurityManager, isEncapsulationCC, } from "@zwave-js/core"; import { MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; // Respond to Scheme Get with Scheme Report const respondToSchemeGet = { handleCC(controller, self, receivedCC) { if (receivedCC instanceof SecurityCCSchemeGet) { // This essentially means that the device is going to be bootstrapped // with Security S0. We need to set up the security manager accordingly // with the temporary key. const tempKey = new Uint8Array(16).fill(0x00); self.securityManagers.securityManager = new SecurityManager({ ownNodeId: self.id, networkKey: tempKey, nonceTimeout: 100000, }); // Now respond to the Scheme Get const cc = new SecurityCCSchemeReport({ nodeId: controller.ownNodeId, }); return { action: "sendCC", cc }; } }, }; // Respond to S0 Nonce Get const respondToS0NonceGet = { handleCC(controller, self, receivedCC) { const sm0Node = self.securityManagers.securityManager; if (!sm0Node) return; if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce(controller.ownNodeId, 8); const cc = new SecurityCCNonceReport({ nodeId: controller.ownNodeId, nonce, }); return { action: "sendCC", cc }; } }, }; // Respond to Network Key Set with Network Key Verify const respondToNetworkKeySet = { async handleCC(controller, self, receivedCC) { if (receivedCC instanceof SecurityCCNetworkKeySet) { // Update the node's security manager to use the received network key const receivedKey = receivedCC.networkKey; self.securityManagers.securityManager.networkKey = receivedKey; const response = new SecurityCCNetworkKeyVerify({ nodeId: controller.ownNodeId, }); return { action: "sendCC", cc: response }; } }, }; // Respond to S0 Commands Supported Get const respondToS0CommandsSupportedGet = { async handleCC(controller, self, receivedCC) { if (receivedCC instanceof SecurityCCCommandsSupportedGet) { // Determine securely supported CCs from the mock node's implementedCCs const supportedCCs = [...self.implementedCCs.entries()] .filter(([cc, info]) => info.secure === true && !isEncapsulationCC(cc)) .map(([cc]) => cc); const response = new SecurityCCCommandsSupportedReport({ nodeId: controller.ownNodeId, supportedCCs, controlledCCs: [], reportsToFollow: 0, }); return { action: "sendCC", cc: response }; } }, }; // Parse and unwrap Security CC commands. const encapsulateS0CC = { async transformIncomingCC(controller, self, receivedCC) { // We don't support sequenced commands here if (receivedCC instanceof SecurityCCCommandEncapsulation) { await receivedCC.mergePartialCCs([], { sourceNodeId: controller.ownNodeId, __internalIsMockNode: true, frameType: "singlecast", ...self.encodingContext, ...self.securityManagers, }); // Return the unwrapped command if (receivedCC.encapsulated) { return receivedCC.encapsulated; } } return receivedCC; }, async transformResponse(controller, self, receivedCC, response) { // Ensure that responses to S0-encapsulated CCs are also S0-encapsulated if (response.action === "sendCC" && receivedCC instanceof CommandClass && receivedCC.isEncapsulatedWith(CommandClasses.Security) && !response.cc.isEncapsulatedWith(CommandClasses.Security)) { // The mock node does not have the magic for automatically // encapsulating commands, so we have to do it ourselves here. // This requires a nonce exchange. const nonceGet = new SecurityCCNonceGet({ nodeId: response.cc.nodeId, }); await self.sendToController(createMockZWaveRequestFrame(nonceGet, { ackRequested: false, })); const nonceReport = await self.expectControllerFrame((resp) => resp.type === MockZWaveFrameType.Request && resp.payload instanceof SecurityCCNonceReport, { timeout: 1000 }); const receiverNonce = nonceReport.payload.nonce; // Encapsulate the response const encapsulated = SecurityCC.encapsulate(self.id, self.securityManagers.securityManager, response.cc); encapsulated.nonce = receiverNonce; response.cc = encapsulated; } return response; }, }; export const SecurityCCHooks = [ encapsulateS0CC, ]; export const SecurityCCBehaviors = [ respondToSchemeGet, respondToS0NonceGet, respondToNetworkKeySet, respondToS0CommandsSupportedGet, ]; //# sourceMappingURL=Security.js.map