zwave-js 14.2.0 → 14.3.1
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/Utils.d.ts +1 -1
- package/build/cjs/Utils.js +6 -2
- package/build/cjs/Utils.js.map +2 -2
- package/build/cjs/index_safe.js.map +2 -2
- package/build/cjs/lib/_version.d.ts +1 -1
- package/build/cjs/lib/_version.js +1 -1
- package/build/cjs/lib/_version.js.map +1 -1
- package/build/cjs/lib/controller/Controller.js +13 -13
- package/build/cjs/lib/controller/Controller.js.map +2 -2
- package/build/cjs/lib/controller/FirmwareUpdateService.js +3 -6
- package/build/cjs/lib/controller/FirmwareUpdateService.js.map +3 -3
- package/build/cjs/lib/driver/Driver.js +18 -19
- package/build/cjs/lib/driver/Driver.js.map +2 -2
- package/build/cjs/lib/node/Node.d.ts +2 -1
- package/build/cjs/lib/node/Node.js +22 -9
- package/build/cjs/lib/node/Node.js.map +2 -2
- package/build/cjs/lib/node/mixins/70_FirmwareUpdate.js +3 -4
- package/build/cjs/lib/node/mixins/70_FirmwareUpdate.js.map +2 -2
- package/build/cjs/lib/telemetry/statistics.js +4 -4
- package/build/cjs/lib/telemetry/statistics.js.map +2 -2
- package/build/cjs/lib/zniffer/Zniffer.js +10 -10
- package/build/cjs/lib/zniffer/Zniffer.js.map +2 -2
- package/build/esm/Utils.d.ts +1 -1
- package/build/esm/Utils.d.ts.map +1 -1
- package/build/esm/Utils.js +1 -1
- package/build/esm/Utils.js.map +1 -1
- package/build/esm/index_safe.d.ts.map +1 -1
- package/build/esm/index_safe.js +1 -0
- package/build/esm/index_safe.js.map +1 -1
- package/build/esm/lib/_version.d.ts +1 -1
- package/build/esm/lib/_version.js +1 -1
- package/build/esm/lib/controller/Controller.d.ts.map +1 -1
- package/build/esm/lib/controller/Controller.js +16 -14
- package/build/esm/lib/controller/Controller.js.map +1 -1
- package/build/esm/lib/controller/FirmwareUpdateService.d.ts.map +1 -1
- package/build/esm/lib/controller/FirmwareUpdateService.js +5 -11
- package/build/esm/lib/controller/FirmwareUpdateService.js.map +1 -1
- package/build/esm/lib/driver/Driver.d.ts.map +1 -1
- package/build/esm/lib/driver/Driver.js +19 -20
- package/build/esm/lib/driver/Driver.js.map +1 -1
- package/build/esm/lib/node/Node.d.ts +2 -1
- package/build/esm/lib/node/Node.d.ts.map +1 -1
- package/build/esm/lib/node/Node.js +27 -9
- package/build/esm/lib/node/Node.js.map +1 -1
- package/build/esm/lib/node/mixins/70_FirmwareUpdate.d.ts.map +1 -1
- package/build/esm/lib/node/mixins/70_FirmwareUpdate.js +1 -2
- package/build/esm/lib/node/mixins/70_FirmwareUpdate.js.map +1 -1
- package/build/esm/lib/telemetry/statistics.d.ts.map +1 -1
- package/build/esm/lib/telemetry/statistics.js +7 -9
- package/build/esm/lib/telemetry/statistics.js.map +1 -1
- package/build/esm/lib/zniffer/Zniffer.d.ts.map +1 -1
- package/build/esm/lib/zniffer/Zniffer.js +12 -10
- package/build/esm/lib/zniffer/Zniffer.js.map +1 -1
- package/package.json +11 -11
|
@@ -34,7 +34,6 @@ __export(FirmwareUpdateService_exports, {
|
|
|
34
34
|
module.exports = __toCommonJS(FirmwareUpdateService_exports);
|
|
35
35
|
var import_core = require("@zwave-js/core");
|
|
36
36
|
var import_shared = require("@zwave-js/shared");
|
|
37
|
-
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
38
37
|
function serviceURL() {
|
|
39
38
|
return process.env.ZWAVEJS_FW_SERVICE_URL || "https://firmware.zwave-js.io";
|
|
40
39
|
}
|
|
@@ -60,7 +59,7 @@ function cleanCache() {
|
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
async function cachedGot(config) {
|
|
63
|
-
const hash =
|
|
62
|
+
const hash = import_shared.Bytes.view(await (0, import_core.digest)("sha-256", import_shared.Bytes.from(JSON.stringify(config.json)))).toString("hex");
|
|
64
63
|
const cacheKey = `${config.method}:${config.url.toString()}:${hash}`;
|
|
65
64
|
if (requestCache.has(cacheKey)) {
|
|
66
65
|
const cached = requestCache.get(cacheKey);
|
|
@@ -200,10 +199,8 @@ async function downloadFirmwareUpdate(file) {
|
|
|
200
199
|
filename = requestedPathname;
|
|
201
200
|
}
|
|
202
201
|
const format = (0, import_core.guessFirmwareFileFormat)(filename, rawData);
|
|
203
|
-
const firmware = (0, import_core.
|
|
204
|
-
const
|
|
205
|
-
hasher.update(firmware.data);
|
|
206
|
-
const actualHash = hasher.digest("hex");
|
|
202
|
+
const firmware = await (0, import_core.extractFirmwareAsync)(rawData, format);
|
|
203
|
+
const actualHash = import_shared.Bytes.view(await (0, import_core.digest)("sha-256", firmware.data)).toString("hex");
|
|
207
204
|
if (actualHash !== expectedHash) {
|
|
208
205
|
throw new import_core.ZWaveError(`Integrity check failed. Expected hash ${expectedHash}, got ${actualHash}`, import_core.ZWaveErrorCodes.FWUpdateService_IntegrityCheckFailed);
|
|
209
206
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/controller/FirmwareUpdateService.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\ttype Firmware,\n\tRFRegion,\n\tZWaveError,\n\tZWaveErrorCodes,\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;AAAA,
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["import {\n\ttype Firmware,\n\tRFRegion,\n\tZWaveError,\n\tZWaveErrorCodes,\n\tdigest,\n\textractFirmwareAsync,\n\tguessFirmwareFileFormat,\n} from \"@zwave-js/core\";\nimport { Bytes, formatId } from \"@zwave-js/shared\";\nimport type { Headers, OptionsOfTextResponseBody } from \"got\";\nimport type PQueue from \"p-queue\";\nimport type {\n\tFirmwareUpdateDeviceID,\n\tFirmwareUpdateFileInfo,\n\tFirmwareUpdateInfo,\n\tFirmwareUpdateServiceResponse,\n} from \"./_Types.js\";\n\nfunction serviceURL(): string {\n\treturn process.env.ZWAVEJS_FW_SERVICE_URL || \"https://firmware.zwave-js.io\";\n}\nconst DOWNLOAD_TIMEOUT = 60000;\n// const MAX_FIRMWARE_SIZE = 10 * 1024 * 1024; // 10MB should be enough for any conceivable Z-Wave chip\n\nconst MAX_CACHE_SECONDS = 60 * 60 * 24; // Cache for a day at max\nconst CLEAN_CACHE_INTERVAL_MS = 60 * 60 * 1000; // Remove stale entries from the cache every hour\n\nconst requestCache = new Map<string, CachedRequest<unknown>>();\ninterface CachedRequest<T> {\n\tresponse: T;\n\tstaleDate: number;\n}\n\n// Queue requests to the firmware update service. Only allow few parallel requests so we can make some use of the cache.\nlet requestQueue: PQueue | undefined;\n\nlet cleanCacheTimeout: NodeJS.Timeout | undefined;\nfunction cleanCache() {\n\tif (cleanCacheTimeout) {\n\t\tclearTimeout(cleanCacheTimeout);\n\t\tcleanCacheTimeout = undefined;\n\t}\n\n\tconst now = Date.now();\n\tfor (const [key, cached] of requestCache) {\n\t\tif (cached.staleDate < now) {\n\t\t\trequestCache.delete(key);\n\t\t}\n\t}\n\n\tif (requestCache.size > 0) {\n\t\tcleanCacheTimeout = setTimeout(\n\t\t\tcleanCache,\n\t\t\tCLEAN_CACHE_INTERVAL_MS,\n\t\t).unref();\n\t}\n}\n\nasync function cachedGot<T>(config: OptionsOfTextResponseBody): Promise<T> {\n\t// Replaces got's built-in cache functionality because it uses Keyv internally\n\t// which apparently has some issues: https://github.com/zwave-js/node-zwave-js/issues/5404\n\n\tconst hash = Bytes.view(\n\t\tawait digest(\n\t\t\t\"sha-256\",\n\t\t\tBytes.from(JSON.stringify(config.json)),\n\t\t),\n\t).toString(\"hex\");\n\tconst cacheKey = `${config.method}:${config.url!.toString()}:${hash}`;\n\n\t// Return cached requests if they are not stale yet\n\tif (requestCache.has(cacheKey)) {\n\t\tconst cached = requestCache.get(cacheKey)!;\n\t\tif (cached.staleDate > Date.now()) {\n\t\t\treturn cached.response as T;\n\t\t}\n\t}\n\n\tconst { got } = await import(\"got\");\n\tconst response = await got(config);\n\tconst responseJson = JSON.parse(response.body) as T;\n\n\t// Check if we can cache the response\n\tif (response.statusCode === 200 && response.headers[\"cache-control\"]) {\n\t\tconst cacheControl = response.headers[\"cache-control\"];\n\n\t\tlet maxAge: number | undefined;\n\t\tconst maxAgeMatch = cacheControl.match(/max-age=(\\d+)/);\n\t\tif (maxAgeMatch) {\n\t\t\tmaxAge = Math.max(0, parseInt(maxAgeMatch[1], 10));\n\t\t}\n\n\t\tif (maxAge) {\n\t\t\tlet currentAge: number;\n\t\t\tif (response.headers.age) {\n\t\t\t\tcurrentAge = parseInt(response.headers.age, 10);\n\t\t\t} else if (response.headers.date) {\n\t\t\t\tcurrentAge = (Date.now() - Date.parse(response.headers.date))\n\t\t\t\t\t/ 1000;\n\t\t\t} else {\n\t\t\t\tcurrentAge = 0;\n\t\t\t}\n\t\t\tcurrentAge = Math.max(0, currentAge);\n\n\t\t\tif (maxAge > currentAge) {\n\t\t\t\trequestCache.set(cacheKey, {\n\t\t\t\t\tresponse: responseJson,\n\t\t\t\t\tstaleDate: Date.now()\n\t\t\t\t\t\t+ Math.min(MAX_CACHE_SECONDS, maxAge - currentAge)\n\t\t\t\t\t\t\t* 1000,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Regularly clean the cache\n\tif (!cleanCacheTimeout) {\n\t\tcleanCacheTimeout = setTimeout(\n\t\t\tcleanCache,\n\t\t\tCLEAN_CACHE_INTERVAL_MS,\n\t\t).unref();\n\t}\n\n\treturn responseJson;\n}\n\nfunction hasExtension(pathname: string): boolean {\n\treturn /\\.[a-z0-9_]+$/i.test(pathname);\n}\n\nexport interface GetAvailableFirmwareUpdateOptions {\n\tuserAgent: string;\n\tapiKey?: string;\n\tincludePrereleases?: boolean;\n}\n\n/** Converts the RF region to a format the update service understands */\nfunction rfRegionToUpdateServiceRegion(\n\trfRegion?: RFRegion,\n): string | undefined {\n\tswitch (rfRegion) {\n\t\tcase RFRegion[\"Default (EU)\"]:\n\t\tcase RFRegion.Europe:\n\t\t\treturn \"europe\";\n\t\tcase RFRegion.USA:\n\t\tcase RFRegion[\"USA (Long Range)\"]:\n\t\t\treturn \"usa\";\n\t\tcase RFRegion[\"Australia/New Zealand\"]:\n\t\t\treturn \"australia/new zealand\";\n\t\tcase RFRegion[\"Hong Kong\"]:\n\t\t\treturn \"hong kong\";\n\t\tcase RFRegion.India:\n\t\t\treturn \"india\";\n\t\tcase RFRegion.Israel:\n\t\t\treturn \"israel\";\n\t\tcase RFRegion.Russia:\n\t\t\treturn \"russia\";\n\t\tcase RFRegion.China:\n\t\t\treturn \"china\";\n\t\tcase RFRegion.Japan:\n\t\t\treturn \"japan\";\n\t\tcase RFRegion.Korea:\n\t\t\treturn \"korea\";\n\t}\n}\n\n/**\n * Retrieves the available firmware updates for the node with the given fingerprint.\n * Returns the service response or `undefined` in case of an error.\n */\nexport async function getAvailableFirmwareUpdates(\n\tdeviceId: FirmwareUpdateDeviceID,\n\toptions: GetAvailableFirmwareUpdateOptions,\n): Promise<FirmwareUpdateInfo[]> {\n\tconst headers: Headers = {\n\t\t\"User-Agent\": options.userAgent,\n\t\t\"Content-Type\": \"application/json\",\n\t};\n\tif (options.apiKey) {\n\t\theaders[\"X-API-Key\"] = options.apiKey;\n\t}\n\n\tconst body: Record<string, string> = {\n\t\tmanufacturerId: formatId(deviceId.manufacturerId),\n\t\tproductType: formatId(deviceId.productType),\n\t\tproductId: formatId(deviceId.productId),\n\t\tfirmwareVersion: deviceId.firmwareVersion,\n\t};\n\tconst rfRegion = rfRegionToUpdateServiceRegion(deviceId.rfRegion);\n\tif (rfRegion) {\n\t\tbody.region = rfRegion;\n\t}\n\n\t// Prereleases and/or RF region-specific updates are only available in v3\n\tconst apiVersion = options.includePrereleases || !!rfRegion ? \"v3\" : \"v1\";\n\n\tconst config: OptionsOfTextResponseBody = {\n\t\tmethod: \"POST\",\n\t\turl: `${serviceURL()}/api/${apiVersion}/updates`,\n\t\tjson: body,\n\t\t// Consider re-enabling this instead of using cachedGot()\n\t\t// At the moment, the built-in caching has some issues though, so we stick\n\t\t// with our own implementation\n\t\t// cache: requestCache,\n\t\t// cacheOptions: {\n\t\t// \tshared: false,\n\t\t// },\n\t\theaders,\n\t};\n\n\tif (!requestQueue) {\n\t\t// I just love ESM\n\t\tconst PQueue = (await import(\"p-queue\")).default;\n\t\trequestQueue = new PQueue({ concurrency: 2 });\n\t}\n\t// Weird types...\n\tconst result = (\n\t\tawait requestQueue.add(() => cachedGot(config))\n\t) as FirmwareUpdateServiceResponse[];\n\n\t// Remember the device ID in the response, so we can use it later\n\t// to ensure the update is for the correct device\n\treturn result.map((update) => ({\n\t\tdevice: deviceId,\n\t\t...update,\n\t\tchannel: update.channel ?? \"stable\",\n\t}));\n}\n\nexport async function downloadFirmwareUpdate(\n\tfile: FirmwareUpdateFileInfo,\n): Promise<Firmware> {\n\tconst [hashAlgorithm, expectedHash] = file.integrity.split(\":\", 2);\n\n\tif (hashAlgorithm !== \"sha256\") {\n\t\tthrow new ZWaveError(\n\t\t\t`Unsupported hash algorithm ${hashAlgorithm} for integrity check`,\n\t\t\tZWaveErrorCodes.Argument_Invalid,\n\t\t);\n\t}\n\t// TODO: Make request abort-able (requires AbortController, Node 14.17+ / Node 16)\n\n\t// Download the firmware file\n\tconst { got } = await import(\"got\");\n\tconst downloadResponse = await got.get(file.url, {\n\t\ttimeout: { request: DOWNLOAD_TIMEOUT },\n\t\tresponseType: \"buffer\",\n\t\t// TODO: figure out how to do maxContentLength: MAX_FIRMWARE_SIZE,\n\t});\n\n\tconst rawData = downloadResponse.body;\n\n\tconst requestedPathname = new URL(file.url).pathname;\n\t// The response may be redirected, so the filename information may be different\n\t// from the requested URL\n\tlet actualPathname: string | undefined;\n\ttry {\n\t\tactualPathname = new URL(downloadResponse.url).pathname;\n\t} catch {\n\t\t// ignore\n\t}\n\n\t// Infer the file type from the content-disposition header or the filename\n\tlet filename: string;\n\tif (\n\t\tdownloadResponse.headers[\"content-disposition\"]?.startsWith(\n\t\t\t\"attachment; filename=\",\n\t\t)\n\t) {\n\t\tfilename = downloadResponse.headers[\"content-disposition\"]\n\t\t\t.split(\"filename=\")[1]\n\t\t\t.replace(/^\"/, \"\")\n\t\t\t.replace(/[\";]$/, \"\");\n\t} else if (actualPathname && hasExtension(actualPathname)) {\n\t\tfilename = actualPathname;\n\t} else {\n\t\tfilename = requestedPathname;\n\t}\n\n\t// Extract the raw data\n\tconst format = guessFirmwareFileFormat(filename, rawData);\n\tconst firmware = await extractFirmwareAsync(rawData, format);\n\n\t// Ensure the hash matches\n\tconst actualHash = Bytes.view(\n\t\tawait digest(\"sha-256\", firmware.data),\n\t).toString(\"hex\");\n\n\tif (actualHash !== expectedHash) {\n\t\tthrow new ZWaveError(\n\t\t\t`Integrity check failed. Expected hash ${expectedHash}, got ${actualHash}`,\n\t\t\tZWaveErrorCodes.FWUpdateService_IntegrityCheckFailed,\n\t\t);\n\t}\n\n\treturn {\n\t\tdata: firmware.data,\n\t\t// Don't trust the guessed firmware target, use the one from the provided info\n\t\tfirmwareTarget: file.target,\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
|
@@ -50,7 +50,6 @@ var import_arrays = require("alcalzone-shared/arrays");
|
|
|
50
50
|
var import_async = require("alcalzone-shared/async");
|
|
51
51
|
var import_deferred_promise = require("alcalzone-shared/deferred-promise");
|
|
52
52
|
var import_typeguards = require("alcalzone-shared/typeguards");
|
|
53
|
-
var import_node_crypto = require("node:crypto");
|
|
54
53
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
55
54
|
var import_node_os = __toESM(require("node:os"), 1);
|
|
56
55
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
@@ -507,10 +506,10 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
507
506
|
if (this._learnModeAuthenticatedKeyPair == void 0) {
|
|
508
507
|
const privateKey = this.cacheGet(import_NetworkCache.cacheKeys.controller.privateKey);
|
|
509
508
|
if (privateKey) {
|
|
510
|
-
this._learnModeAuthenticatedKeyPair = (0, import_core.
|
|
509
|
+
this._learnModeAuthenticatedKeyPair = (0, import_core.keyPairFromRawECDHPrivateKeySync)(privateKey);
|
|
511
510
|
} else {
|
|
512
|
-
this._learnModeAuthenticatedKeyPair = (0, import_core.
|
|
513
|
-
this.cacheSet(import_NetworkCache.cacheKeys.controller.privateKey, (0, import_core.
|
|
511
|
+
this._learnModeAuthenticatedKeyPair = (0, import_core.generateECDHKeyPairSync)();
|
|
512
|
+
this.cacheSet(import_NetworkCache.cacheKeys.controller.privateKey, (0, import_core.extractRawECDHPrivateKeySync)(this._learnModeAuthenticatedKeyPair.privateKey));
|
|
514
513
|
}
|
|
515
514
|
}
|
|
516
515
|
return this._learnModeAuthenticatedKeyPair;
|
|
@@ -962,7 +961,7 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
962
961
|
}
|
|
963
962
|
if (this._options.securityKeys && Object.keys(this._options.securityKeys).some((key) => key.startsWith("S2_") && key in import_core.SecurityClass && (0, import_core.securityClassIsS2)(import_core.SecurityClass[key]))) {
|
|
964
963
|
this.driverLog.print("At least one network key for S2 configured, enabling S2 security manager...");
|
|
965
|
-
this._securityManager2 =
|
|
964
|
+
this._securityManager2 = await import_core.SecurityManager2.create();
|
|
966
965
|
for (const secClass of [
|
|
967
966
|
"S2_Unauthenticated",
|
|
968
967
|
"S2_Authenticated",
|
|
@@ -971,7 +970,7 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
971
970
|
]) {
|
|
972
971
|
const key = this._options.securityKeys[secClass];
|
|
973
972
|
if (key) {
|
|
974
|
-
this._securityManager2.
|
|
973
|
+
await this._securityManager2.setKeyAsync(import_core.SecurityClass[secClass], key);
|
|
975
974
|
}
|
|
976
975
|
}
|
|
977
976
|
} else {
|
|
@@ -979,12 +978,12 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
979
978
|
}
|
|
980
979
|
if (this._options.securityKeysLongRange?.S2_AccessControl || this._options.securityKeysLongRange?.S2_Authenticated) {
|
|
981
980
|
this.driverLog.print("At least one network key for Z-Wave Long Range configured, enabling security manager...");
|
|
982
|
-
this._securityManagerLR =
|
|
981
|
+
this._securityManagerLR = await import_core.SecurityManager2.create();
|
|
983
982
|
if (this._options.securityKeysLongRange?.S2_AccessControl) {
|
|
984
|
-
this._securityManagerLR.
|
|
983
|
+
await this._securityManagerLR.setKeyAsync(import_core.SecurityClass.S2_AccessControl, this._options.securityKeysLongRange.S2_AccessControl);
|
|
985
984
|
}
|
|
986
985
|
if (this._options.securityKeysLongRange?.S2_Authenticated) {
|
|
987
|
-
this._securityManagerLR.
|
|
986
|
+
await this._securityManagerLR.setKeyAsync(import_core.SecurityClass.S2_Authenticated, this._options.securityKeysLongRange.S2_Authenticated);
|
|
988
987
|
}
|
|
989
988
|
} else {
|
|
990
989
|
this.driverLog.print("No network key for Z-Wave Long Range configured, communication won't work!", "warn");
|
|
@@ -1000,18 +999,18 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
1000
999
|
]).filter((v) => v[1] != void 0);
|
|
1001
1000
|
if (securityKeysLongRange.length) {
|
|
1002
1001
|
this.driverLog.print("At least one network key for Z-Wave Long Range found in cache, enabling security manager...");
|
|
1003
|
-
this._securityManagerLR =
|
|
1002
|
+
this._securityManagerLR = await import_core.SecurityManager2.create();
|
|
1004
1003
|
for (const [sc, key] of securityKeysLongRange) {
|
|
1005
|
-
this._securityManagerLR.
|
|
1004
|
+
await this._securityManagerLR.setKeyAsync(sc, key);
|
|
1006
1005
|
}
|
|
1007
1006
|
} else if (this._options.securityKeysLongRange?.S2_AccessControl || this._options.securityKeysLongRange?.S2_Authenticated) {
|
|
1008
1007
|
this.driverLog.print("Fallback to configured network keys for Z-Wave Long Range, enabling security manager...");
|
|
1009
|
-
this._securityManagerLR =
|
|
1008
|
+
this._securityManagerLR = await import_core.SecurityManager2.create();
|
|
1010
1009
|
if (this._options.securityKeysLongRange?.S2_AccessControl) {
|
|
1011
|
-
this._securityManagerLR.
|
|
1010
|
+
await this._securityManagerLR.setKeyAsync(import_core.SecurityClass.S2_AccessControl, this._options.securityKeysLongRange.S2_AccessControl);
|
|
1012
1011
|
}
|
|
1013
1012
|
if (this._options.securityKeysLongRange?.S2_Authenticated) {
|
|
1014
|
-
this._securityManagerLR.
|
|
1013
|
+
await this._securityManagerLR.setKeyAsync(import_core.SecurityClass.S2_Authenticated, this._options.securityKeysLongRange.S2_Authenticated);
|
|
1015
1014
|
}
|
|
1016
1015
|
} else {
|
|
1017
1016
|
this.driverLog.print("No network key for Z-Wave Long Range configured, communication won't work!", "warn");
|
|
@@ -1041,13 +1040,13 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
1041
1040
|
]).filter((v) => v[1] != void 0);
|
|
1042
1041
|
if (securityKeys.length) {
|
|
1043
1042
|
this.driverLog.print("At least one network key for S2 found in cache, enabling S2 security manager...");
|
|
1044
|
-
this._securityManager2 =
|
|
1043
|
+
this._securityManager2 = await import_core.SecurityManager2.create();
|
|
1045
1044
|
for (const [sc, key] of securityKeys) {
|
|
1046
|
-
this._securityManager2.
|
|
1045
|
+
await this._securityManager2.setKeyAsync(sc, key);
|
|
1047
1046
|
}
|
|
1048
1047
|
} else if (this._options.securityKeys && Object.keys(this._options.securityKeys).some((key) => key.startsWith("S2_") && key in import_core.SecurityClass && (0, import_core.securityClassIsS2)(import_core.SecurityClass[key]))) {
|
|
1049
1048
|
this.driverLog.print("Fallback to configured network keys for S2, enabling S2 security manager...");
|
|
1050
|
-
this._securityManager2 =
|
|
1049
|
+
this._securityManager2 = await import_core.SecurityManager2.create();
|
|
1051
1050
|
for (const secClass of [
|
|
1052
1051
|
"S2_Unauthenticated",
|
|
1053
1052
|
"S2_Authenticated",
|
|
@@ -1056,7 +1055,7 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
1056
1055
|
]) {
|
|
1057
1056
|
const key = this._options.securityKeys[secClass];
|
|
1058
1057
|
if (key) {
|
|
1059
|
-
this._securityManager2.
|
|
1058
|
+
await this._securityManager2.setKeyAsync(import_core.SecurityClass[secClass], key);
|
|
1060
1059
|
}
|
|
1061
1060
|
}
|
|
1062
1061
|
} else {
|
|
@@ -1342,7 +1341,7 @@ class Driver extends import_shared.TypedEventEmitter {
|
|
|
1342
1341
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1343
1342
|
async getUUID() {
|
|
1344
1343
|
if (!this._valueDB.has("uuid")) {
|
|
1345
|
-
this._valueDB.set("uuid", (0,
|
|
1344
|
+
this._valueDB.set("uuid", import_shared.Bytes.view((0, import_core.randomBytes)(32)).toString("hex"));
|
|
1346
1345
|
}
|
|
1347
1346
|
const ret = this._valueDB.get("uuid");
|
|
1348
1347
|
return ret;
|