zigbee-herdsman
Version:
An open source ZigBee gateway solution with node.js.
190 lines • 8.76 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fromLegacyBackup = exports.fromUnifiedBackup = exports.toUnifiedBackup = void 0;
const ZStackStructs = __importStar(require("../adapter/z-stack/structs"));
const ZStackUtils = __importStar(require("../adapter/z-stack/utils"));
const mz_1 = require("mz");
const path = __importStar(require("path"));
/**
* Converts internal backup format to unified backup storage format as described by
* [zigpy/open-coordinator-backup](https://github.com/zigpy/open-coordinator-backup).
*
* @param backup Backup to create unified backup format from.
*/
const toUnifiedBackup = async (backup) => {
const panIdBuffer = Buffer.alloc(2);
panIdBuffer.writeUInt16BE(backup.networkOptions.panId);
const packageInfo = JSON.parse((await mz_1.fs.readFile(path.join(__dirname, "../../", "package.json"))).toString());
/* istanbul ignore next */
return {
metadata: {
format: "zigpy/open-coordinator-backup",
version: 1,
source: `${packageInfo.name}@${packageInfo.version}`,
internal: {
date: new Date().toISOString(),
...(backup.znp) ? {
znpVersion: [null, undefined].includes(backup.znp?.version) ? undefined : backup.znp?.version
} : undefined,
...(backup.ezsp) ? {
ezspVersion: [null, undefined].includes(backup.ezsp?.version) ? undefined : backup.ezsp?.version
} : undefined,
}
},
stack_specific: {
...(backup.znp) ? {
zstack: {
tclk_seed: backup.znp?.trustCenterLinkKeySeed?.toString("hex") || undefined
}
} : undefined,
...(backup.ezsp) ? {
ezsp: {
hashed_tclk: backup.ezsp?.hashed_tclk?.toString("hex") || undefined
}
} : undefined
},
coordinator_ieee: backup.coordinatorIeeeAddress?.toString("hex") || null,
pan_id: panIdBuffer.toString("hex"),
extended_pan_id: backup.networkOptions.extendedPanId.toString("hex"),
nwk_update_id: backup.networkUpdateId || 0,
security_level: backup.securityLevel || null,
channel: backup.logicalChannel,
channel_mask: backup.networkOptions.channelList,
network_key: {
key: backup.networkOptions.networkKey.toString("hex"),
sequence_number: backup.networkKeyInfo.sequenceNumber,
frame_counter: backup.networkKeyInfo.frameCounter
},
devices: backup.devices.map(device => {
const nwkAddressBuffer = Buffer.alloc(2);
nwkAddressBuffer.writeUInt16BE(device.networkAddress);
return {
nwk_address: nwkAddressBuffer.toString("hex"),
ieee_address: device.ieeeAddress.toString("hex"),
is_child: device.isDirectChild,
link_key: !device.linkKey ? undefined : {
key: device.linkKey.key.toString("hex"),
rx_counter: device.linkKey.rxCounter,
tx_counter: device.linkKey.txCounter
}
};
}),
};
};
exports.toUnifiedBackup = toUnifiedBackup;
/**
* Converts unified backup storage format to internal backup format.
*
* @param backup Unified format to convert to internal backup format.
*/
const fromUnifiedBackup = (backup) => {
const tclkSeedString = backup.stack_specific?.zstack?.tclk_seed || null;
/* istanbul ignore next */
return {
networkOptions: {
panId: Buffer.from(backup.pan_id, "hex").readUInt16BE(),
extendedPanId: Buffer.from(backup.extended_pan_id, "hex"),
channelList: backup.channel_mask,
networkKey: Buffer.from(backup.network_key.key, "hex"),
networkKeyDistribute: false
},
logicalChannel: backup.channel,
networkKeyInfo: {
sequenceNumber: backup.network_key.sequence_number,
frameCounter: backup.network_key.frame_counter
},
coordinatorIeeeAddress: backup.coordinator_ieee ? Buffer.from(backup.coordinator_ieee, "hex") : null,
securityLevel: backup.security_level || null,
networkUpdateId: backup.nwk_update_id || null,
devices: backup.devices.map(device => ({
networkAddress: device.nwk_address ? Buffer.from(device.nwk_address, "hex").readUInt16BE() : Buffer.from("fffe", "hex").readUInt16BE(),
ieeeAddress: Buffer.from(device.ieee_address, "hex"),
isDirectChild: typeof device.is_child === "boolean" ? device.is_child : true,
linkKey: !device.link_key ? undefined : {
key: Buffer.from(device.link_key.key, "hex"),
rxCounter: device.link_key.rx_counter,
txCounter: device.link_key.tx_counter
}
})),
znp: {
version: backup.metadata.internal?.znpVersion || undefined,
trustCenterLinkKeySeed: tclkSeedString ? Buffer.from(tclkSeedString, "hex") : undefined,
},
ezsp: {
version: backup.metadata.internal?.ezspVersion || undefined,
hashed_tclk: backup.stack_specific?.ezsp?.hashed_tclk ? Buffer.from(backup.stack_specific.ezsp.hashed_tclk, "hex") : undefined,
}
};
};
exports.fromUnifiedBackup = fromUnifiedBackup;
/**
* Converts legacy Zigbee2MQTT format to internal backup format.
*
* @param backup Legacy format to convert.
*/
const fromLegacyBackup = (backup) => {
if (!backup.data.ZCD_NV_NIB) {
throw new Error("Backup corrupted - missing NIB");
}
else if (!backup.data.ZCD_NV_NWK_ACTIVE_KEY_INFO) {
throw new Error("Backup corrupted - missing active key info");
}
else if (!backup.data.ZCD_NV_PRECFGKEY_ENABLE) {
throw new Error("Backup corrupted - missing pre-configured key enable attribute");
}
else if (!backup.data.ZCD_NV_EX_NWK_SEC_MATERIAL_TABLE && !backup.data.ZCD_NV_LEGACY_NWK_SEC_MATERIAL_TABLE_START) {
throw new Error("Backup corrupted - missing network security material table");
}
else if (!backup.data.ZCD_NV_EXTADDR) {
throw new Error("Backup corrupted - missing adapter IEEE address NV entry");
}
const ieeeAddress = Buffer.from(backup.data.ZCD_NV_EXTADDR.value).reverse();
const nib = ZStackStructs.nib(Buffer.from(backup.data.ZCD_NV_NIB.value));
const activeKeyInfo = ZStackStructs.nwkKeyDescriptor(Buffer.from(backup.data.ZCD_NV_NWK_ACTIVE_KEY_INFO.value));
const preconfiguredKeyEnabled = backup.data.ZCD_NV_PRECFGKEY_ENABLE.value[0] !== 0x00;
const nwkSecMaterialSource = backup.data.ZCD_NV_EX_NWK_SEC_MATERIAL_TABLE || backup.data.ZCD_NV_LEGACY_NWK_SEC_MATERIAL_TABLE_START;
const nwkSecMaterialEntry = ZStackStructs.nwkSecMaterialDescriptorEntry(Buffer.from(nwkSecMaterialSource.value));
return {
networkOptions: {
panId: nib.nwkPanId,
extendedPanId: nib.extendedPANID,
channelList: ZStackUtils.unpackChannelList(nib.channelList),
networkKey: activeKeyInfo.key,
networkKeyDistribute: preconfiguredKeyEnabled
},
logicalChannel: nib.nwkLogicalChannel,
networkKeyInfo: {
sequenceNumber: activeKeyInfo.keySeqNum,
frameCounter: nwkSecMaterialEntry.FrameCounter
},
coordinatorIeeeAddress: ieeeAddress,
securityLevel: nib.SecurityLevel,
networkUpdateId: nib.nwkUpdateId,
devices: []
};
};
exports.fromLegacyBackup = fromLegacyBackup;
//# sourceMappingURL=backup.js.map