smart-home-engine 1.53.2 → 1.53.4
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/dist/web/assets/{index-BsO7OQRT.css → index-Cp--IWao.css} +1 -1
- package/dist/web/assets/index-DPRtP55L.js +298 -0
- package/dist/web/assets/{tsMode-DDvVFMm4.js → tsMode-Ci4l56iF.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/matter/controller.js +105 -4
- package/dist/web/assets/index-lCqN_GjH.js +0 -298
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-
|
|
1
|
+
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-DPRtP55L.js";/*!-----------------------------------------------------------------------------
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
|
|
4
4
|
* Released under the MIT license
|
package/dist/web/index.html
CHANGED
|
@@ -175,10 +175,10 @@
|
|
|
175
175
|
}
|
|
176
176
|
})();
|
|
177
177
|
</script>
|
|
178
|
-
<script type="module" crossorigin src="/assets/index-
|
|
178
|
+
<script type="module" crossorigin src="/assets/index-DPRtP55L.js"></script>
|
|
179
179
|
<link rel="modulepreload" crossorigin href="/assets/monaco-langs-DKJI_o9J.js">
|
|
180
180
|
<link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
|
|
181
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
181
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Cp--IWao.css">
|
|
182
182
|
</head>
|
|
183
183
|
<body>
|
|
184
184
|
<div id="app"></div>
|
package/package.json
CHANGED
package/src/matter/controller.js
CHANGED
|
@@ -81,9 +81,15 @@ function _resolveEndpoint(node, endpointIdOrName) {
|
|
|
81
81
|
throw new Error(`Endpoint not found: ${endpointIdOrName}`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Recursively convert values so the result is JSON-serialisable: BigInt to a number (or a string
|
|
86
|
+
* beyond 2^53), byte arrays to `{ $bytes: "<hex>" }` — JSON.stringify would turn a Uint8Array into
|
|
87
|
+
* an object of numbered keys, which the UI cannot tell from a struct.
|
|
88
|
+
*/
|
|
85
89
|
function _jsonSafe(v) {
|
|
86
90
|
if (typeof v === 'bigint') return v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v.toString();
|
|
91
|
+
if (ArrayBuffer.isView(v)) return { $bytes: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString('hex') };
|
|
92
|
+
if (v instanceof ArrayBuffer) return { $bytes: Buffer.from(v).toString('hex') };
|
|
87
93
|
if (Array.isArray(v)) return v.map(_jsonSafe);
|
|
88
94
|
if (v !== null && typeof v === 'object') {
|
|
89
95
|
const out = {};
|
|
@@ -361,7 +367,18 @@ async function commission(options) {
|
|
|
361
367
|
}
|
|
362
368
|
|
|
363
369
|
async function _commissionInner(options) {
|
|
364
|
-
const { discoveryAddress, ...
|
|
370
|
+
const { discoveryAddress, ...rest } = options;
|
|
371
|
+
// matter.js (0.17.0 … 0.17.9) passes an absent regulatory location and country through
|
|
372
|
+
// CommissioningClient as `undefined`, which overrides the commissioner's own default "XX":
|
|
373
|
+
// every Thread or Wi-Fi device then fails at SetRegulatoryConfig ("Missing mandatory field
|
|
374
|
+
// countryCode"). "XX" (unknown country) is always valid; IndoorOutdoor is used only when the
|
|
375
|
+
// device reports that capability, otherwise the device keeps its own location.
|
|
376
|
+
const { GeneralCommissioning } = require('@matter/main/clusters');
|
|
377
|
+
const commissionOpts = {
|
|
378
|
+
regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
|
|
379
|
+
regulatoryCountryCode: 'XX',
|
|
380
|
+
...rest,
|
|
381
|
+
};
|
|
365
382
|
let clientNode;
|
|
366
383
|
if (discoveryAddress) {
|
|
367
384
|
const colonIdx = discoveryAddress.lastIndexOf(':');
|
|
@@ -437,7 +454,7 @@ function getEndpoints(nodeId) {
|
|
|
437
454
|
const attrs = {};
|
|
438
455
|
if (clusterState && typeof clusterState === 'object') {
|
|
439
456
|
for (const [k, v] of Object.entries(clusterState)) {
|
|
440
|
-
attrs[k] =
|
|
457
|
+
attrs[k] = _attrValue(clusterName, k, v);
|
|
441
458
|
}
|
|
442
459
|
}
|
|
443
460
|
clusters.push({ name: clusterName, attrs });
|
|
@@ -627,6 +644,88 @@ async function sendCommand(nodeId, endpointId, clusterName, commandName, args) {
|
|
|
627
644
|
* @param {object} node ClientNode
|
|
628
645
|
* @param {string} nodeId decimal string
|
|
629
646
|
*/
|
|
647
|
+
/** Matter's attribute OIDs (1.3.6.1.4.1.37244.1.x, Matter core spec 6.5.6.1) by name. */
|
|
648
|
+
const MATTER_DN_OIDS = {
|
|
649
|
+
'1.3.6.1.4.1.37244.1.1': 'matter-node-id',
|
|
650
|
+
'1.3.6.1.4.1.37244.1.2': 'matter-firmware-signing-id',
|
|
651
|
+
'1.3.6.1.4.1.37244.1.3': 'matter-icac-id',
|
|
652
|
+
'1.3.6.1.4.1.37244.1.4': 'matter-rcac-id',
|
|
653
|
+
'1.3.6.1.4.1.37244.1.5': 'matter-fabric-id',
|
|
654
|
+
'1.3.6.1.4.1.37244.1.6': 'matter-noc-cat',
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
/** node's X509Certificate distinguished name ("oid=value\n…") with Matter's OIDs named */
|
|
658
|
+
function _matterDn(dn) {
|
|
659
|
+
return String(dn || '')
|
|
660
|
+
.split('\n')
|
|
661
|
+
.filter(Boolean)
|
|
662
|
+
.map((part) => {
|
|
663
|
+
const eq = part.indexOf('=');
|
|
664
|
+
const key = part.slice(0, eq);
|
|
665
|
+
return `${MATTER_DN_OIDS[key] || key}=${part.slice(eq + 1)}`;
|
|
666
|
+
})
|
|
667
|
+
.join(', ');
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* A Matter operational certificate (TLV, as the OperationalCredentials cluster holds it) as
|
|
672
|
+
* `{ $cert: { kind, subject, validFrom, validTo, fingerprint, pem } }`: converted to X.509 DER by
|
|
673
|
+
* matter.js, read back by node's X509Certificate. Anything that does not convert stays `$bytes`.
|
|
674
|
+
*/
|
|
675
|
+
function _certValue(kind, bytes) {
|
|
676
|
+
if (!ArrayBuffer.isView(bytes)) return _jsonSafe(bytes);
|
|
677
|
+
try {
|
|
678
|
+
const { Noc, Icac, Rcac } = require('@matter/protocol');
|
|
679
|
+
const cert = { NOC: Noc, ICAC: Icac, RCAC: Rcac }[kind].fromTlv(bytes);
|
|
680
|
+
const der = Buffer.from(cert.asSignedDer());
|
|
681
|
+
const x509 = new (require('crypto').X509Certificate)(der);
|
|
682
|
+
const lines = der
|
|
683
|
+
.toString('base64')
|
|
684
|
+
.match(/.{1,64}/g)
|
|
685
|
+
.join('\n');
|
|
686
|
+
return {
|
|
687
|
+
$cert: {
|
|
688
|
+
kind,
|
|
689
|
+
// Matter's own fields (nodeId, fabricId, rcacId, icacId, caseAuthenticatedTags …)
|
|
690
|
+
subject: _jsonSafe(cert.cert.subject),
|
|
691
|
+
issuer: _jsonSafe(cert.cert.issuer),
|
|
692
|
+
// the same as X.509 distinguished names, with Matter's OIDs named
|
|
693
|
+
subjectDn: _matterDn(x509.subject),
|
|
694
|
+
issuerDn: _matterDn(x509.issuer),
|
|
695
|
+
serialNumber: x509.serialNumber,
|
|
696
|
+
validFrom: new Date(x509.validFrom).toISOString(),
|
|
697
|
+
validTo: new Date(x509.validTo).toISOString(),
|
|
698
|
+
ca: x509.ca,
|
|
699
|
+
// key usage, extended key usage, basic constraints, key identifiers — all the
|
|
700
|
+
// certificate carries; Matter operational certificates have no CRL distribution point
|
|
701
|
+
extensions: _jsonSafe(cert.cert.extensions),
|
|
702
|
+
fingerprint: x509.fingerprint256,
|
|
703
|
+
pem: `-----BEGIN CERTIFICATE-----\n${lines}\n-----END CERTIFICATE-----`,
|
|
704
|
+
},
|
|
705
|
+
};
|
|
706
|
+
} catch {
|
|
707
|
+
return _jsonSafe(bytes);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/** An attribute value for the UI and the REST API: certificates as PEM, the rest via _jsonSafe. */
|
|
712
|
+
function _attrValue(clusterName, attrName, value) {
|
|
713
|
+
if (clusterName === 'operationalCredentials') {
|
|
714
|
+
if (attrName === 'nocs' && Array.isArray(value)) {
|
|
715
|
+
return value.map((entry) => {
|
|
716
|
+
const out = _jsonSafe(entry);
|
|
717
|
+
if (entry?.noc) out.noc = _certValue('NOC', entry.noc);
|
|
718
|
+
if (entry?.icac) out.icac = _certValue('ICAC', entry.icac);
|
|
719
|
+
return out;
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
if (attrName === 'trustedRootCertificates' && Array.isArray(value)) {
|
|
723
|
+
return value.map((root) => _certValue('RCAC', root));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return _jsonSafe(value);
|
|
727
|
+
}
|
|
728
|
+
|
|
630
729
|
function _broadcastNodeAttributes(node, nodeId) {
|
|
631
730
|
if (!_broadcast) return;
|
|
632
731
|
if (_attrBroadcastNodes.has(nodeId)) return;
|
|
@@ -653,7 +752,7 @@ function _broadcastNodeAttributes(node, nodeId) {
|
|
|
653
752
|
endpointId,
|
|
654
753
|
clusterName,
|
|
655
754
|
attrName,
|
|
656
|
-
value:
|
|
755
|
+
value: _attrValue(clusterName, attrName, value),
|
|
657
756
|
ts: Date.now(),
|
|
658
757
|
});
|
|
659
758
|
// Device/endpoint labels feed the device list — rebroadcast it
|
|
@@ -795,6 +894,8 @@ function isStarted() {
|
|
|
795
894
|
}
|
|
796
895
|
|
|
797
896
|
module.exports = {
|
|
897
|
+
// for the unit tests: the value conversion, without a running controller
|
|
898
|
+
_attrValue,
|
|
798
899
|
init,
|
|
799
900
|
close,
|
|
800
901
|
isStarted,
|