@matter/protocol 0.14.0 → 0.14.1-alpha.0-20250606-a9bcd03f9
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/cjs/action/server/AccessControl.d.ts +5 -7
- package/dist/cjs/action/server/AccessControl.d.ts.map +1 -1
- package/dist/cjs/action/server/AccessControl.js.map +1 -1
- package/dist/cjs/action/server/AttributeWriteResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/AttributeWriteResponse.js +23 -0
- package/dist/cjs/action/server/AttributeWriteResponse.js.map +1 -1
- package/dist/cjs/action/server/CommandInvokeResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/CommandInvokeResponse.js +24 -1
- package/dist/cjs/action/server/CommandInvokeResponse.js.map +1 -1
- package/dist/cjs/action/server/DataResponse.d.ts +1 -1
- package/dist/cjs/action/server/DataResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/Subject.d.ts +25 -0
- package/dist/cjs/action/server/Subject.d.ts.map +1 -0
- package/dist/cjs/action/server/Subject.js +54 -0
- package/dist/cjs/action/server/Subject.js.map +6 -0
- package/dist/cjs/action/server/index.d.ts +1 -0
- package/dist/cjs/action/server/index.d.ts.map +1 -1
- package/dist/cjs/action/server/index.js +1 -0
- package/dist/cjs/action/server/index.js.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.d.ts +2 -2
- package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
- package/dist/cjs/cluster/client/AttributeClient.d.ts +3 -3
- package/dist/cjs/cluster/client/AttributeClient.d.ts.map +1 -1
- package/dist/cjs/cluster/client/AttributeClient.js +14 -2
- package/dist/cjs/cluster/client/AttributeClient.js.map +1 -1
- package/dist/cjs/cluster/client/ClusterClient.d.ts +3 -2
- package/dist/cjs/cluster/client/ClusterClient.d.ts.map +1 -1
- package/dist/cjs/cluster/client/ClusterClient.js +60 -1
- package/dist/cjs/cluster/client/ClusterClient.js.map +1 -1
- package/dist/cjs/cluster/client/ClusterClientTypes.d.ts +33 -8
- package/dist/cjs/cluster/client/ClusterClientTypes.d.ts.map +1 -1
- package/dist/cjs/cluster/client/EventClient.d.ts +3 -3
- package/dist/cjs/cluster/client/EventClient.d.ts.map +1 -1
- package/dist/cjs/cluster/client/EventClient.js +7 -0
- package/dist/cjs/cluster/client/EventClient.js.map +1 -1
- package/dist/cjs/codec/MessageCodec.d.ts.map +1 -1
- package/dist/cjs/codec/MessageCodec.js +31 -6
- package/dist/cjs/codec/MessageCodec.js.map +1 -1
- package/dist/cjs/fabric/Fabric.d.ts +20 -30
- package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
- package/dist/cjs/fabric/Fabric.js +38 -62
- package/dist/cjs/fabric/Fabric.js.map +2 -2
- package/dist/cjs/fabric/FabricManager.d.ts.map +1 -1
- package/dist/cjs/fabric/FabricManager.js +10 -4
- package/dist/cjs/fabric/FabricManager.js.map +1 -1
- package/dist/cjs/groups/FabricGroupsManager.d.ts +46 -0
- package/dist/cjs/groups/FabricGroupsManager.d.ts.map +1 -0
- package/dist/cjs/groups/FabricGroupsManager.js +155 -0
- package/dist/cjs/groups/FabricGroupsManager.js.map +6 -0
- package/dist/cjs/groups/Groups.d.ts +34 -0
- package/dist/cjs/groups/Groups.d.ts.map +1 -0
- package/dist/cjs/groups/Groups.js +89 -0
- package/dist/cjs/groups/Groups.js.map +6 -0
- package/dist/cjs/groups/KeySets.d.ts +64 -0
- package/dist/cjs/groups/KeySets.d.ts.map +1 -0
- package/dist/cjs/groups/KeySets.js +179 -0
- package/dist/cjs/groups/KeySets.js.map +6 -0
- package/dist/cjs/groups/MessagingState.d.ts +24 -0
- package/dist/cjs/groups/MessagingState.d.ts.map +1 -0
- package/dist/cjs/groups/MessagingState.js +91 -0
- package/dist/cjs/groups/MessagingState.js.map +6 -0
- package/dist/cjs/groups/index.d.ts +8 -0
- package/dist/cjs/groups/index.d.ts.map +1 -0
- package/dist/cjs/groups/index.js +25 -0
- package/dist/cjs/groups/index.js.map +6 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interaction/AccessControlManager.d.ts +4 -13
- package/dist/cjs/interaction/AccessControlManager.d.ts.map +1 -1
- package/dist/cjs/interaction/AccessControlManager.js +38 -47
- package/dist/cjs/interaction/AccessControlManager.js.map +1 -1
- package/dist/cjs/interaction/InteractionClient.d.ts +5 -4
- package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionClient.js +53 -3
- package/dist/cjs/interaction/InteractionClient.js.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.js +15 -0
- package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
- package/dist/cjs/interaction/Subscription.d.ts +3 -3
- package/dist/cjs/interaction/Subscription.d.ts.map +1 -1
- package/dist/cjs/interaction/Subscription.js.map +1 -1
- package/dist/cjs/peer/PeerAddress.d.ts +1 -0
- package/dist/cjs/peer/PeerAddress.d.ts.map +1 -1
- package/dist/cjs/peer/PeerAddress.js +5 -0
- package/dist/cjs/peer/PeerAddress.js.map +1 -1
- package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.js +31 -2
- package/dist/cjs/peer/PeerSet.js.map +1 -1
- package/dist/cjs/protocol/ChannelManager.d.ts.map +1 -1
- package/dist/cjs/protocol/ChannelManager.js +7 -8
- package/dist/cjs/protocol/ChannelManager.js.map +1 -1
- package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeManager.js +39 -25
- package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
- package/dist/cjs/protocol/MessageExchange.d.ts +1 -1
- package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/cjs/protocol/MessageExchange.js +32 -4
- package/dist/cjs/protocol/MessageExchange.js.map +1 -1
- package/dist/cjs/protocol/MessageReceptionState.d.ts +1 -1
- package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -1
- package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
- package/dist/cjs/session/GroupSession.d.ts +56 -0
- package/dist/cjs/session/GroupSession.d.ts.map +1 -0
- package/dist/cjs/session/GroupSession.js +188 -0
- package/dist/cjs/session/GroupSession.js.map +6 -0
- package/dist/cjs/session/InsecureSession.d.ts +2 -1
- package/dist/cjs/session/InsecureSession.d.ts.map +1 -1
- package/dist/cjs/session/InsecureSession.js +3 -2
- package/dist/cjs/session/InsecureSession.js.map +1 -1
- package/dist/cjs/session/NodeSession.d.ts +88 -0
- package/dist/cjs/session/NodeSession.d.ts.map +1 -0
- package/dist/cjs/session/NodeSession.js +318 -0
- package/dist/cjs/session/NodeSession.js.map +6 -0
- package/dist/cjs/session/SecureSession.d.ts +10 -75
- package/dist/cjs/session/SecureSession.d.ts.map +1 -1
- package/dist/cjs/session/SecureSession.js +9 -280
- package/dist/cjs/session/SecureSession.js.map +2 -2
- package/dist/cjs/session/Session.d.ts +6 -5
- package/dist/cjs/session/Session.d.ts.map +1 -1
- package/dist/cjs/session/Session.js +11 -1
- package/dist/cjs/session/Session.js.map +1 -1
- package/dist/cjs/session/SessionManager.d.ts +27 -9
- package/dist/cjs/session/SessionManager.d.ts.map +1 -1
- package/dist/cjs/session/SessionManager.js +83 -5
- package/dist/cjs/session/SessionManager.js.map +2 -2
- package/dist/cjs/session/case/CaseClient.d.ts +1 -1
- package/dist/cjs/session/case/CaseClient.js +2 -2
- package/dist/cjs/session/case/CaseClient.js.map +1 -1
- package/dist/cjs/session/index.d.ts +2 -0
- package/dist/cjs/session/index.d.ts.map +1 -1
- package/dist/cjs/session/index.js +2 -0
- package/dist/cjs/session/index.js.map +1 -1
- package/dist/cjs/session/pase/PaseClient.d.ts +1 -1
- package/dist/esm/action/server/AccessControl.d.ts +5 -7
- package/dist/esm/action/server/AccessControl.d.ts.map +1 -1
- package/dist/esm/action/server/AccessControl.js.map +1 -1
- package/dist/esm/action/server/AttributeWriteResponse.d.ts.map +1 -1
- package/dist/esm/action/server/AttributeWriteResponse.js +23 -0
- package/dist/esm/action/server/AttributeWriteResponse.js.map +1 -1
- package/dist/esm/action/server/CommandInvokeResponse.d.ts.map +1 -1
- package/dist/esm/action/server/CommandInvokeResponse.js +24 -1
- package/dist/esm/action/server/CommandInvokeResponse.js.map +1 -1
- package/dist/esm/action/server/DataResponse.d.ts +1 -1
- package/dist/esm/action/server/DataResponse.d.ts.map +1 -1
- package/dist/esm/action/server/Subject.d.ts +25 -0
- package/dist/esm/action/server/Subject.d.ts.map +1 -0
- package/dist/esm/action/server/Subject.js +34 -0
- package/dist/esm/action/server/Subject.js.map +6 -0
- package/dist/esm/action/server/index.d.ts +1 -0
- package/dist/esm/action/server/index.d.ts.map +1 -1
- package/dist/esm/action/server/index.js +1 -0
- package/dist/esm/action/server/index.js.map +1 -1
- package/dist/esm/certificate/DeviceCertification.d.ts +2 -2
- package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/esm/certificate/DeviceCertification.js.map +1 -1
- package/dist/esm/cluster/client/AttributeClient.d.ts +3 -3
- package/dist/esm/cluster/client/AttributeClient.d.ts.map +1 -1
- package/dist/esm/cluster/client/AttributeClient.js +13 -1
- package/dist/esm/cluster/client/AttributeClient.js.map +1 -1
- package/dist/esm/cluster/client/ClusterClient.d.ts +3 -2
- package/dist/esm/cluster/client/ClusterClient.d.ts.map +1 -1
- package/dist/esm/cluster/client/ClusterClient.js +61 -2
- package/dist/esm/cluster/client/ClusterClient.js.map +1 -1
- package/dist/esm/cluster/client/ClusterClientTypes.d.ts +33 -8
- package/dist/esm/cluster/client/ClusterClientTypes.d.ts.map +1 -1
- package/dist/esm/cluster/client/EventClient.d.ts +3 -3
- package/dist/esm/cluster/client/EventClient.d.ts.map +1 -1
- package/dist/esm/cluster/client/EventClient.js +7 -0
- package/dist/esm/cluster/client/EventClient.js.map +1 -1
- package/dist/esm/codec/MessageCodec.d.ts.map +1 -1
- package/dist/esm/codec/MessageCodec.js +41 -7
- package/dist/esm/codec/MessageCodec.js.map +1 -1
- package/dist/esm/fabric/Fabric.d.ts +20 -30
- package/dist/esm/fabric/Fabric.d.ts.map +1 -1
- package/dist/esm/fabric/Fabric.js +38 -62
- package/dist/esm/fabric/Fabric.js.map +2 -2
- package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
- package/dist/esm/fabric/FabricManager.js +10 -4
- package/dist/esm/fabric/FabricManager.js.map +1 -1
- package/dist/esm/groups/FabricGroupsManager.d.ts +46 -0
- package/dist/esm/groups/FabricGroupsManager.d.ts.map +1 -0
- package/dist/esm/groups/FabricGroupsManager.js +135 -0
- package/dist/esm/groups/FabricGroupsManager.js.map +6 -0
- package/dist/esm/groups/Groups.d.ts +34 -0
- package/dist/esm/groups/Groups.d.ts.map +1 -0
- package/dist/esm/groups/Groups.js +69 -0
- package/dist/esm/groups/Groups.js.map +6 -0
- package/dist/esm/groups/KeySets.d.ts +64 -0
- package/dist/esm/groups/KeySets.d.ts.map +1 -0
- package/dist/esm/groups/KeySets.js +159 -0
- package/dist/esm/groups/KeySets.js.map +6 -0
- package/dist/esm/groups/MessagingState.d.ts +24 -0
- package/dist/esm/groups/MessagingState.d.ts.map +1 -0
- package/dist/esm/groups/MessagingState.js +71 -0
- package/dist/esm/groups/MessagingState.js.map +6 -0
- package/dist/esm/groups/index.d.ts +8 -0
- package/dist/esm/groups/index.d.ts.map +1 -0
- package/dist/esm/groups/index.js +8 -0
- package/dist/esm/groups/index.js.map +6 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interaction/AccessControlManager.d.ts +4 -13
- package/dist/esm/interaction/AccessControlManager.d.ts.map +1 -1
- package/dist/esm/interaction/AccessControlManager.js +39 -48
- package/dist/esm/interaction/AccessControlManager.js.map +1 -1
- package/dist/esm/interaction/InteractionClient.d.ts +5 -4
- package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionClient.js +54 -4
- package/dist/esm/interaction/InteractionClient.js.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.js +15 -0
- package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
- package/dist/esm/interaction/Subscription.d.ts +3 -3
- package/dist/esm/interaction/Subscription.d.ts.map +1 -1
- package/dist/esm/interaction/Subscription.js.map +1 -1
- package/dist/esm/peer/PeerAddress.d.ts +1 -0
- package/dist/esm/peer/PeerAddress.d.ts.map +1 -1
- package/dist/esm/peer/PeerAddress.js +5 -0
- package/dist/esm/peer/PeerAddress.js.map +1 -1
- package/dist/esm/peer/PeerSet.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.js +33 -3
- package/dist/esm/peer/PeerSet.js.map +1 -1
- package/dist/esm/protocol/ChannelManager.d.ts.map +1 -1
- package/dist/esm/protocol/ChannelManager.js +7 -8
- package/dist/esm/protocol/ChannelManager.js.map +1 -1
- package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeManager.js +41 -27
- package/dist/esm/protocol/ExchangeManager.js.map +1 -1
- package/dist/esm/protocol/MessageExchange.d.ts +1 -1
- package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/esm/protocol/MessageExchange.js +39 -5
- package/dist/esm/protocol/MessageExchange.js.map +1 -1
- package/dist/esm/protocol/MessageReceptionState.d.ts +1 -1
- package/dist/esm/securechannel/SecureChannelProtocol.js +2 -2
- package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
- package/dist/esm/session/GroupSession.d.ts +56 -0
- package/dist/esm/session/GroupSession.d.ts.map +1 -0
- package/dist/esm/session/GroupSession.js +177 -0
- package/dist/esm/session/GroupSession.js.map +6 -0
- package/dist/esm/session/InsecureSession.d.ts +2 -1
- package/dist/esm/session/InsecureSession.d.ts.map +1 -1
- package/dist/esm/session/InsecureSession.js +3 -2
- package/dist/esm/session/InsecureSession.js.map +1 -1
- package/dist/esm/session/NodeSession.d.ts +88 -0
- package/dist/esm/session/NodeSession.d.ts.map +1 -0
- package/dist/esm/session/NodeSession.js +298 -0
- package/dist/esm/session/NodeSession.js.map +6 -0
- package/dist/esm/session/SecureSession.d.ts +10 -75
- package/dist/esm/session/SecureSession.d.ts.map +1 -1
- package/dist/esm/session/SecureSession.js +10 -291
- package/dist/esm/session/SecureSession.js.map +2 -2
- package/dist/esm/session/Session.d.ts +6 -5
- package/dist/esm/session/Session.d.ts.map +1 -1
- package/dist/esm/session/Session.js +12 -2
- package/dist/esm/session/Session.js.map +1 -1
- package/dist/esm/session/SessionManager.d.ts +27 -9
- package/dist/esm/session/SessionManager.d.ts.map +1 -1
- package/dist/esm/session/SessionManager.js +84 -6
- package/dist/esm/session/SessionManager.js.map +1 -1
- package/dist/esm/session/case/CaseClient.d.ts +1 -1
- package/dist/esm/session/case/CaseClient.js +2 -2
- package/dist/esm/session/case/CaseClient.js.map +1 -1
- package/dist/esm/session/index.d.ts +2 -0
- package/dist/esm/session/index.d.ts.map +1 -1
- package/dist/esm/session/index.js +2 -0
- package/dist/esm/session/index.js.map +1 -1
- package/dist/esm/session/pase/PaseClient.d.ts +1 -1
- package/package.json +6 -6
- package/src/action/server/AccessControl.ts +4 -7
- package/src/action/server/AttributeWriteResponse.ts +29 -7
- package/src/action/server/CommandInvokeResponse.ts +28 -7
- package/src/action/server/DataResponse.ts +1 -1
- package/src/action/server/Subject.ts +45 -0
- package/src/action/server/index.ts +1 -0
- package/src/certificate/DeviceCertification.ts +2 -2
- package/src/cluster/client/AttributeClient.ts +15 -3
- package/src/cluster/client/ClusterClient.ts +90 -4
- package/src/cluster/client/ClusterClientTypes.ts +38 -9
- package/src/cluster/client/EventClient.ts +9 -2
- package/src/codec/MessageCodec.ts +49 -8
- package/src/fabric/Fabric.ts +51 -85
- package/src/fabric/FabricManager.ts +11 -4
- package/src/groups/FabricGroupsManager.ts +164 -0
- package/src/groups/Groups.ts +81 -0
- package/src/groups/KeySets.ts +194 -0
- package/src/groups/MessagingState.ts +76 -0
- package/src/groups/index.ts +8 -0
- package/src/index.ts +1 -0
- package/src/interaction/AccessControlManager.ts +49 -81
- package/src/interaction/InteractionClient.ts +66 -6
- package/src/interaction/InteractionMessenger.ts +15 -0
- package/src/interaction/Subscription.ts +3 -3
- package/src/peer/PeerAddress.ts +4 -0
- package/src/peer/PeerSet.ts +39 -4
- package/src/protocol/ChannelManager.ts +7 -9
- package/src/protocol/ExchangeManager.ts +51 -35
- package/src/protocol/MessageExchange.ts +42 -7
- package/src/protocol/MessageReceptionState.ts +2 -2
- package/src/securechannel/SecureChannelProtocol.ts +2 -2
- package/src/session/GroupSession.ts +223 -0
- package/src/session/InsecureSession.ts +3 -2
- package/src/session/NodeSession.ts +367 -0
- package/src/session/SecureSession.ts +14 -363
- package/src/session/Session.ts +17 -6
- package/src/session/SessionManager.ts +94 -14
- package/src/session/case/CaseClient.ts +2 -2
- package/src/session/index.ts +2 -3
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { capitalize, Diagnostic, Logger, Merge } from "#general";
|
|
7
|
+
import { capitalize, Diagnostic, ImplementationError, Logger, Merge } from "#general";
|
|
8
8
|
import {
|
|
9
9
|
Attribute,
|
|
10
10
|
AttributeId,
|
|
@@ -31,18 +31,37 @@ import {
|
|
|
31
31
|
AttributeClientValues,
|
|
32
32
|
ClusterClientObj,
|
|
33
33
|
EventClients,
|
|
34
|
+
GroupClusterClientObj,
|
|
34
35
|
SignatureFromCommandSpec,
|
|
36
|
+
SignatureFromCommandSpecWithoutResponse,
|
|
35
37
|
} from "./ClusterClientTypes.js";
|
|
36
38
|
import { createEventClient } from "./EventClient.js";
|
|
37
39
|
|
|
38
40
|
const logger = Logger.get("ClusterClient");
|
|
39
41
|
|
|
42
|
+
export function GroupClusterClient<const T extends ClusterType>(
|
|
43
|
+
clusterDef: T,
|
|
44
|
+
interactionClient: InteractionClient,
|
|
45
|
+
globalAttributeValues: Partial<AttributeClientValues<GlobalAttributes<T["features"]>>> = {},
|
|
46
|
+
): GroupClusterClientObj<T> {
|
|
47
|
+
if (!interactionClient.isGroupAddress) {
|
|
48
|
+
throw new Error("GroupClusterClient must be used with a GroupAddress InteractionClient");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return ClusterClient(clusterDef, undefined, interactionClient, globalAttributeValues);
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
export function ClusterClient<const T extends ClusterType>(
|
|
41
55
|
clusterDef: T,
|
|
42
|
-
endpointId: EndpointNumber,
|
|
56
|
+
endpointId: EndpointNumber | undefined,
|
|
43
57
|
interactionClient: InteractionClient,
|
|
44
58
|
globalAttributeValues: Partial<AttributeClientValues<GlobalAttributes<T["features"]>>> = {},
|
|
45
59
|
): ClusterClientObj<T> {
|
|
60
|
+
const isGroupAddress = interactionClient.isGroupAddress;
|
|
61
|
+
if (isGroupAddress !== (endpointId === undefined)) {
|
|
62
|
+
throw new Error("Endpoint ID must be defined for a Non-Group ClusterClient");
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
function addAttributeToResult(attribute: Attribute<any, any>, attributeName: string) {
|
|
47
66
|
(attributes as any)[attributeName] = createAttributeClient(
|
|
48
67
|
attribute,
|
|
@@ -59,6 +78,10 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
59
78
|
requestFromRemote?: boolean,
|
|
60
79
|
isFabricFiltered = true,
|
|
61
80
|
) => {
|
|
81
|
+
if (isGroupAddress) {
|
|
82
|
+
throw new ImplementationError("Group cluster clients do not support reading attributes");
|
|
83
|
+
}
|
|
84
|
+
|
|
62
85
|
try {
|
|
63
86
|
return await (attributes as any)[attributeName].get(requestFromRemote, isFabricFiltered);
|
|
64
87
|
} catch (e) {
|
|
@@ -77,6 +100,10 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
77
100
|
knownDataVersion?: number,
|
|
78
101
|
isFabricFiltered?: boolean,
|
|
79
102
|
) => {
|
|
103
|
+
if (isGroupAddress) {
|
|
104
|
+
throw new ImplementationError("Group cluster clients do not support subscribing attributes");
|
|
105
|
+
}
|
|
106
|
+
|
|
80
107
|
(attributes as any)[attributeName].addListener(listener);
|
|
81
108
|
return (attributes as any)[attributeName].subscribe(
|
|
82
109
|
minIntervalS,
|
|
@@ -86,9 +113,17 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
86
113
|
);
|
|
87
114
|
};
|
|
88
115
|
result[`add${capitalizedAttributeName}AttributeListener`] = <T>(listener: (value: T) => void) => {
|
|
116
|
+
if (isGroupAddress) {
|
|
117
|
+
throw new ImplementationError("Group cluster clients do not support subscribing attributes");
|
|
118
|
+
}
|
|
119
|
+
|
|
89
120
|
(attributes as any)[attributeName].addListener(listener);
|
|
90
121
|
};
|
|
91
122
|
result[`remove${capitalizedAttributeName}AttributeListener`] = <T>(listener: (value: T) => void) => {
|
|
123
|
+
if (isGroupAddress) {
|
|
124
|
+
throw new ImplementationError("Group cluster clients do not support subscribing attributes");
|
|
125
|
+
}
|
|
126
|
+
|
|
92
127
|
(attributes as any)[attributeName].removeListener(listener);
|
|
93
128
|
};
|
|
94
129
|
}
|
|
@@ -102,6 +137,10 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
102
137
|
minimumEventNumber?: number | bigint,
|
|
103
138
|
isFabricFiltered?: boolean,
|
|
104
139
|
) => {
|
|
140
|
+
if (isGroupAddress) {
|
|
141
|
+
throw new ImplementationError("Group cluster clients do not support reading events");
|
|
142
|
+
}
|
|
143
|
+
|
|
105
144
|
try {
|
|
106
145
|
return await (events as any)[eventName].get(minimumEventNumber, isFabricFiltered);
|
|
107
146
|
} catch (e) {
|
|
@@ -119,6 +158,10 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
119
158
|
minimumEventNumber?: number | bigint,
|
|
120
159
|
isFabricFiltered?: boolean,
|
|
121
160
|
) => {
|
|
161
|
+
if (isGroupAddress) {
|
|
162
|
+
throw new ImplementationError("Group cluster clients do not support subscribing to events");
|
|
163
|
+
}
|
|
164
|
+
|
|
122
165
|
(events as any)[eventName].addListener(listener);
|
|
123
166
|
return (events as any)[eventName].subscribe(
|
|
124
167
|
minIntervalS,
|
|
@@ -129,9 +172,17 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
129
172
|
);
|
|
130
173
|
};
|
|
131
174
|
result[`add${capitalizedEventName}EventListener`] = <T>(listener: (value: DecodedEventData<T>) => void) => {
|
|
175
|
+
if (isGroupAddress) {
|
|
176
|
+
throw new ImplementationError("Group cluster clients do not support subscribing events");
|
|
177
|
+
}
|
|
178
|
+
|
|
132
179
|
(events as any)[eventName].addListener(listener);
|
|
133
180
|
};
|
|
134
181
|
result[`remove${capitalizedEventName}EventListener`] = <T>(listener: (value: DecodedEventData<T>) => void) => {
|
|
182
|
+
if (isGroupAddress) {
|
|
183
|
+
throw new ImplementationError("Group cluster clients do not support subscribing events");
|
|
184
|
+
}
|
|
185
|
+
|
|
135
186
|
(events as any)[eventName].removeListener(listener);
|
|
136
187
|
};
|
|
137
188
|
}
|
|
@@ -149,7 +200,13 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
149
200
|
} = clusterDef;
|
|
150
201
|
const attributes = <AttributeClients<T["features"], T["attributes"]>>{};
|
|
151
202
|
const events = <EventClients<T["events"]>>{};
|
|
152
|
-
const commands = <
|
|
203
|
+
const commands = <
|
|
204
|
+
{
|
|
205
|
+
[P in keyof T["commands"]]:
|
|
206
|
+
| SignatureFromCommandSpec<T["commands"][P]>
|
|
207
|
+
| SignatureFromCommandSpecWithoutResponse<T["commands"][P]>;
|
|
208
|
+
}
|
|
209
|
+
>{};
|
|
153
210
|
|
|
154
211
|
let reportedFeatures: TypeFromPartialBitSchema<T["features"]> | undefined = undefined;
|
|
155
212
|
// If we have global attribute values we use them to modify
|
|
@@ -178,6 +235,10 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
178
235
|
eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];
|
|
179
236
|
dataVersionFilters?: { endpointId: EndpointNumber; clusterId: ClusterId; dataVersion: number }[];
|
|
180
237
|
}) => {
|
|
238
|
+
if (isGroupAddress) {
|
|
239
|
+
throw new ImplementationError("Group cluster clients do not support subscribing attributes");
|
|
240
|
+
}
|
|
241
|
+
|
|
181
242
|
const {
|
|
182
243
|
minIntervalFloorSeconds,
|
|
183
244
|
maxIntervalCeilingSeconds,
|
|
@@ -237,10 +298,18 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
237
298
|
},
|
|
238
299
|
|
|
239
300
|
isAttributeSupported: (attributeId: AttributeId) => {
|
|
301
|
+
if (isGroupAddress) {
|
|
302
|
+
throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
|
|
303
|
+
}
|
|
304
|
+
|
|
240
305
|
return !!globalAttributeValues?.attributeList?.includes(attributeId);
|
|
241
306
|
},
|
|
242
307
|
|
|
243
308
|
isAttributeSupportedByName: (attributeName: string) => {
|
|
309
|
+
if (isGroupAddress) {
|
|
310
|
+
throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
|
|
311
|
+
}
|
|
312
|
+
|
|
244
313
|
const attribute = (attributes as any)[attributeName];
|
|
245
314
|
if (attribute === undefined) {
|
|
246
315
|
return false;
|
|
@@ -249,10 +318,18 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
249
318
|
},
|
|
250
319
|
|
|
251
320
|
isCommandSupported: (commandId: CommandId) => {
|
|
321
|
+
if (isGroupAddress) {
|
|
322
|
+
throw new ImplementationError("Group cluster clients do not allow to determine command existence.");
|
|
323
|
+
}
|
|
324
|
+
|
|
252
325
|
return !!globalAttributeValues?.acceptedCommandList?.includes(commandId);
|
|
253
326
|
},
|
|
254
327
|
|
|
255
328
|
isCommandSupportedByName: (commandName: string) => {
|
|
329
|
+
if (isGroupAddress) {
|
|
330
|
+
throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
|
|
331
|
+
}
|
|
332
|
+
|
|
256
333
|
const command = commandDef[commandName];
|
|
257
334
|
if (command === undefined) {
|
|
258
335
|
return false;
|
|
@@ -308,8 +385,17 @@ export function ClusterClient<const T extends ClusterType>(
|
|
|
308
385
|
} = {},
|
|
309
386
|
) => {
|
|
310
387
|
const { asTimedRequest, timedRequestTimeoutMs, useExtendedFailSafeMessageResponseTimeout } = options;
|
|
388
|
+
if (isGroupAddress) {
|
|
389
|
+
return interactionClient.invokeWithSuppressedResponse<Command<RequestT, ResponseT, any>>({
|
|
390
|
+
clusterId,
|
|
391
|
+
command: commandDef[commandName],
|
|
392
|
+
request,
|
|
393
|
+
asTimedRequest,
|
|
394
|
+
timedRequestTimeoutMs,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
311
397
|
return interactionClient.invoke<Command<RequestT, ResponseT, any>>({
|
|
312
|
-
endpointId
|
|
398
|
+
endpointId: endpointId!,
|
|
313
399
|
clusterId,
|
|
314
400
|
command: commandDef[commandName],
|
|
315
401
|
request,
|
|
@@ -72,6 +72,23 @@ export type SignatureFromCommandSpec<C extends Command<any, any, any>> = (
|
|
|
72
72
|
useExtendedFailSafeMessageResponseTimeout?: boolean;
|
|
73
73
|
},
|
|
74
74
|
) => Promise<ResponseType<C>>;
|
|
75
|
+
|
|
76
|
+
export type SignatureFromCommandSpecWithoutResponse<C extends Command<any, any, any>> = (
|
|
77
|
+
request: RequestType<C>,
|
|
78
|
+
options?: {
|
|
79
|
+
/** Send this command as a timed request also when not required. Default timeout are 10 seconds. */
|
|
80
|
+
asTimedRequest?: boolean;
|
|
81
|
+
|
|
82
|
+
/** Override the request timeout when the command is sent as times request. Default are 10s. */
|
|
83
|
+
timedRequestTimeoutMs?: number;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Use the extended fail-safe message response timeout of 30 seconds. Use this for all commands
|
|
87
|
+
* executed during an activated FailSafe context!
|
|
88
|
+
*/
|
|
89
|
+
useExtendedFailSafeMessageResponseTimeout?: boolean;
|
|
90
|
+
},
|
|
91
|
+
) => Promise<void>;
|
|
75
92
|
type GetterTypeFromSpec<A extends Attribute<any, any>> =
|
|
76
93
|
A extends OptionalAttribute<infer T, any> ? T | undefined : AttributeJsType<A>;
|
|
77
94
|
type ClientAttributeGetters<A extends Attributes> = Omit<
|
|
@@ -116,6 +133,7 @@ type ClientAttributeListeners<A extends Attributes> = {
|
|
|
116
133
|
};
|
|
117
134
|
|
|
118
135
|
type CommandServers<C extends Commands> = { [P in keyof C]: SignatureFromCommandSpec<C[P]> };
|
|
136
|
+
type NoResponseCommandServers<C extends Commands> = { [P in keyof C]: SignatureFromCommandSpecWithoutResponse<C[P]> };
|
|
119
137
|
|
|
120
138
|
type ClientEventGetters<E extends Events> = {
|
|
121
139
|
[P in keyof E as `get${Capitalize<string & P>}Event`]: (
|
|
@@ -143,8 +161,8 @@ type ClientEventListeners<E extends Events> = {
|
|
|
143
161
|
) => void;
|
|
144
162
|
};
|
|
145
163
|
|
|
146
|
-
/** Strongly typed interface of a cluster client */
|
|
147
|
-
export type
|
|
164
|
+
/** Strongly typed interface of a group cluster client (limited functionalities) */
|
|
165
|
+
export type BaseClusterClientObj<T extends ClusterType = ClusterType> = {
|
|
148
166
|
/**
|
|
149
167
|
* Cluster ID
|
|
150
168
|
* @readonly
|
|
@@ -177,12 +195,6 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
|
|
|
177
195
|
*/
|
|
178
196
|
readonly isUnknown: boolean;
|
|
179
197
|
|
|
180
|
-
/**
|
|
181
|
-
* Endpoint ID the cluster is on.
|
|
182
|
-
* @readonly
|
|
183
|
-
*/
|
|
184
|
-
readonly endpointId: number;
|
|
185
|
-
|
|
186
198
|
/**
|
|
187
199
|
* Supported Features of the cluster
|
|
188
200
|
* @readonly
|
|
@@ -195,6 +207,24 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
|
|
|
195
207
|
* @readonly
|
|
196
208
|
*/
|
|
197
209
|
readonly attributes: AttributeClients<T["features"], T["attributes"]>;
|
|
210
|
+
} & ClientAttributeSetters<T["attributes"]>;
|
|
211
|
+
|
|
212
|
+
export type GroupClusterClientObj<T extends ClusterType = ClusterType> = BaseClusterClientObj<T> & {
|
|
213
|
+
/**
|
|
214
|
+
* Commands of the cluster as object with named keys. This can be used to discover the commands of the cluster
|
|
215
|
+
* programmatically.
|
|
216
|
+
* @readonly
|
|
217
|
+
*/
|
|
218
|
+
readonly commands: NoResponseCommandServers<T["commands"]>;
|
|
219
|
+
} & NoResponseCommandServers<T["commands"]>;
|
|
220
|
+
|
|
221
|
+
/** Strongly typed interface of a cluster client */
|
|
222
|
+
export type ClusterClientObj<T extends ClusterType = ClusterType> = BaseClusterClientObj<T> & {
|
|
223
|
+
/**
|
|
224
|
+
* Endpoint ID the cluster is on.
|
|
225
|
+
* @readonly
|
|
226
|
+
*/
|
|
227
|
+
readonly endpointId: number;
|
|
198
228
|
|
|
199
229
|
/**
|
|
200
230
|
* Events of the cluster as object with named keys. This can be used to discover the events of the cluster
|
|
@@ -236,7 +266,6 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
|
|
|
236
266
|
isCommandSupportedByName: (commandName: string) => boolean;
|
|
237
267
|
} & ClientAttributeGetters<T["attributes"]> &
|
|
238
268
|
ClientGlobalAttributeGetters<T["features"]> &
|
|
239
|
-
ClientAttributeSetters<T["attributes"]> &
|
|
240
269
|
ClientAttributeSubscribers<T["attributes"]> &
|
|
241
270
|
ClientAttributeListeners<T["attributes"]> &
|
|
242
271
|
CommandServers<T["commands"]> &
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { ImplementationError } from "#general";
|
|
7
8
|
import { ClusterId, EndpointNumber, Event, EventId, EventNumber } from "#types";
|
|
8
9
|
import { DecodedEventData } from "../../interaction/EventDataDecoder.js";
|
|
9
10
|
import { InteractionClient } from "../../interaction/InteractionClient.js";
|
|
@@ -14,7 +15,7 @@ import { InteractionClient } from "../../interaction/InteractionClient.js";
|
|
|
14
15
|
export function createEventClient<T>(
|
|
15
16
|
event: Event<T, any>,
|
|
16
17
|
name: string,
|
|
17
|
-
endpointId: EndpointNumber,
|
|
18
|
+
endpointId: EndpointNumber | undefined,
|
|
18
19
|
clusterId: ClusterId,
|
|
19
20
|
interactionClient: InteractionClient,
|
|
20
21
|
): EventClient<T> {
|
|
@@ -32,7 +33,7 @@ export class EventClient<T> {
|
|
|
32
33
|
constructor(
|
|
33
34
|
readonly event: Event<T, any>,
|
|
34
35
|
readonly name: string,
|
|
35
|
-
readonly endpointId: EndpointNumber,
|
|
36
|
+
readonly endpointId: EndpointNumber | undefined,
|
|
36
37
|
readonly clusterId: ClusterId,
|
|
37
38
|
interactionClient: InteractionClient,
|
|
38
39
|
) {
|
|
@@ -44,6 +45,9 @@ export class EventClient<T> {
|
|
|
44
45
|
minimumEventNumber?: EventNumber,
|
|
45
46
|
isFabricFiltered?: boolean,
|
|
46
47
|
): Promise<DecodedEventData<T>[] | undefined> {
|
|
48
|
+
if (this.endpointId === undefined) {
|
|
49
|
+
throw new ImplementationError("Cannot read event without endpointId");
|
|
50
|
+
}
|
|
47
51
|
return await this.#interactionClient.getEvent({
|
|
48
52
|
endpointId: this.endpointId,
|
|
49
53
|
clusterId: this.clusterId,
|
|
@@ -60,6 +64,9 @@ export class EventClient<T> {
|
|
|
60
64
|
minimumEventNumber?: EventNumber,
|
|
61
65
|
isFabricFiltered?: boolean,
|
|
62
66
|
) {
|
|
67
|
+
if (this.endpointId === undefined) {
|
|
68
|
+
throw new ImplementationError("Cannot read event without endpointId");
|
|
69
|
+
}
|
|
63
70
|
return await this.#interactionClient.subscribeEvent({
|
|
64
71
|
endpointId: this.endpointId,
|
|
65
72
|
clusterId: this.clusterId,
|
|
@@ -4,7 +4,16 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Bytes,
|
|
9
|
+
DataReader,
|
|
10
|
+
DataWriter,
|
|
11
|
+
Diagnostic,
|
|
12
|
+
Endian,
|
|
13
|
+
InternalError,
|
|
14
|
+
NotImplementedError,
|
|
15
|
+
UnexpectedDataError,
|
|
16
|
+
} from "#general";
|
|
8
17
|
import { ExchangeLogContext } from "#protocol/index.js";
|
|
9
18
|
import { GroupId, INTERACTION_PROTOCOL_ID, NodeId, SECURE_CHANNEL_PROTOCOL_ID, SecureMessageType } from "#types";
|
|
10
19
|
import { MessageType } from "../interaction/InteractionMessenger.js";
|
|
@@ -84,6 +93,7 @@ const enum SecurityFlag {
|
|
|
84
93
|
HasPrivacyEnhancements = 0b10000000,
|
|
85
94
|
IsControlMessage = 0b01000000,
|
|
86
95
|
HasMessageExtension = 0b00100000,
|
|
96
|
+
SessionTypeMask = 0b00000011,
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
function mapProtocolAndMessageType(protocolId: number, messageType: number): { type: string; for?: string } {
|
|
@@ -129,6 +139,13 @@ export class MessageCodec {
|
|
|
129
139
|
const extensionLength = reader.readUInt16();
|
|
130
140
|
securityExtension = reader.readByteArray(extensionLength);
|
|
131
141
|
}
|
|
142
|
+
|
|
143
|
+
if (header.sessionType === SessionType.Group && !header.isControlMessage) {
|
|
144
|
+
if (payloadHeader.requiresAck || payloadHeader.ackedMessageId) {
|
|
145
|
+
throw new UnexpectedDataError(`Group data messages cannot have requiresAck or ackedMessageId set.`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
132
149
|
return {
|
|
133
150
|
packetHeader: header,
|
|
134
151
|
payloadHeader,
|
|
@@ -176,13 +193,31 @@ export class MessageCodec {
|
|
|
176
193
|
const destNodeId = hasDestNodeId ? NodeId(reader.readUInt64()) : undefined;
|
|
177
194
|
const destGroupId = hasDestGroupId ? GroupId(reader.readUInt16()) : undefined;
|
|
178
195
|
|
|
179
|
-
const sessionType = securityFlags &
|
|
180
|
-
|
|
181
|
-
|
|
196
|
+
const sessionType = securityFlags & SecurityFlag.SessionTypeMask;
|
|
197
|
+
|
|
198
|
+
if (sessionType !== SessionType.Group && sessionType !== SessionType.Unicast) {
|
|
199
|
+
throw new UnexpectedDataError(`Unsupported session type ${sessionType}.`);
|
|
200
|
+
}
|
|
201
|
+
if (sessionType === SessionType.Unicast && hasDestGroupId) {
|
|
202
|
+
throw new UnexpectedDataError(`Unicast session cannot have destination group id.`);
|
|
203
|
+
}
|
|
204
|
+
if (sessionType === SessionType.Group) {
|
|
205
|
+
if (!hasDestGroupId && !hasDestNodeId) {
|
|
206
|
+
throw new UnexpectedDataError(`Group session must have destination group id or destination node id.`);
|
|
207
|
+
}
|
|
208
|
+
if (!hasSourceNodeId) {
|
|
209
|
+
throw new UnexpectedDataError(`Group session must have source node id.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
182
212
|
const hasPrivacyEnhancements = (securityFlags & SecurityFlag.HasPrivacyEnhancements) !== 0;
|
|
183
|
-
if (hasPrivacyEnhancements)
|
|
213
|
+
if (hasPrivacyEnhancements) {
|
|
214
|
+
throw new NotImplementedError(`Privacy enhancements not supported.`);
|
|
215
|
+
}
|
|
184
216
|
const isControlMessage = (securityFlags & SecurityFlag.IsControlMessage) !== 0;
|
|
185
|
-
if (isControlMessage)
|
|
217
|
+
if (isControlMessage) {
|
|
218
|
+
// And also currently not needed because MCP is not relevant
|
|
219
|
+
throw new NotImplementedError(`Control Messages not supported.`);
|
|
220
|
+
}
|
|
186
221
|
const hasMessageExtensions = (securityFlags & SecurityFlag.HasMessageExtension) !== 0;
|
|
187
222
|
|
|
188
223
|
return {
|
|
@@ -207,7 +242,7 @@ export class MessageCodec {
|
|
|
207
242
|
const hasSecuredExtension = (exchangeFlags & PayloadHeaderFlag.HasSecureExtension) !== 0;
|
|
208
243
|
const hasVendorId = (exchangeFlags & PayloadHeaderFlag.HasVendorId) !== 0;
|
|
209
244
|
|
|
210
|
-
const messageType = reader.readUInt8();
|
|
245
|
+
const messageType = reader.readUInt8(); // Protocol Opcode
|
|
211
246
|
const exchangeId = reader.readUInt16();
|
|
212
247
|
const vendorId = hasVendorId ? reader.readUInt16() : COMMON_VENDOR_ID;
|
|
213
248
|
const protocolId = (vendorId << 16) | reader.readUInt16();
|
|
@@ -232,6 +267,12 @@ export class MessageCodec {
|
|
|
232
267
|
sourceNodeId,
|
|
233
268
|
sessionType,
|
|
234
269
|
}: PacketHeader) {
|
|
270
|
+
if (
|
|
271
|
+
sessionType === SessionType.Group &&
|
|
272
|
+
(destGroupId === undefined || sourceNodeId === undefined || destNodeId !== undefined)
|
|
273
|
+
) {
|
|
274
|
+
throw new InternalError(`Group session must have destination group id or source node id.`);
|
|
275
|
+
}
|
|
235
276
|
const writer = new DataWriter(Endian.Little);
|
|
236
277
|
const flags =
|
|
237
278
|
(HEADER_VERSION << 4) |
|
|
@@ -246,7 +287,7 @@ export class MessageCodec {
|
|
|
246
287
|
writer.writeUInt32(messageCounter);
|
|
247
288
|
if (sourceNodeId !== undefined) writer.writeUInt64(sourceNodeId);
|
|
248
289
|
if (destNodeId !== undefined) writer.writeUInt64(destNodeId);
|
|
249
|
-
if (destGroupId !== undefined) writer.
|
|
290
|
+
if (destGroupId !== undefined) writer.writeUInt16(destGroupId);
|
|
250
291
|
return writer.toByteArray();
|
|
251
292
|
}
|
|
252
293
|
|
package/src/fabric/Fabric.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
TlvOperationalCertificate,
|
|
11
11
|
TlvRootCertificate,
|
|
12
12
|
} from "#certificate/CertificateManager.js";
|
|
13
|
-
import { GroupKeyManagement } from "#clusters/group-key-management";
|
|
14
13
|
import {
|
|
15
14
|
BinaryKeyPair,
|
|
16
15
|
Bytes,
|
|
@@ -25,56 +24,19 @@ import {
|
|
|
25
24
|
MatterFlowError,
|
|
26
25
|
MaybePromise,
|
|
27
26
|
PrivateKey,
|
|
27
|
+
StorageContext,
|
|
28
28
|
} from "#general";
|
|
29
|
+
import { FabricGroupsManager, GROUP_SECURITY_INFO } from "#groups/FabricGroupsManager.js";
|
|
29
30
|
import { PeerAddress } from "#peer/PeerAddress.js";
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
31
|
+
import { Session } from "#session/Session.js";
|
|
32
|
+
import { CaseAuthenticatedTag, FabricId, FabricIndex, GroupId, NodeId, VendorId } from "#types";
|
|
32
33
|
|
|
33
34
|
const logger = Logger.get("Fabric");
|
|
34
35
|
|
|
35
36
|
const COMPRESSED_FABRIC_ID_INFO = Bytes.fromString("CompressedFabric");
|
|
36
|
-
const GROUP_SECURITY_INFO = Bytes.fromString("GroupKey v1.0");
|
|
37
37
|
|
|
38
38
|
export class PublicKeyError extends MatterError {}
|
|
39
39
|
|
|
40
|
-
type OperationalGroupKeySet = TypeFromSchema<typeof GroupKeyManagement.TlvGroupKeySet> & {
|
|
41
|
-
operationalEpochKey0: Uint8Array;
|
|
42
|
-
groupSessionId0: number | null;
|
|
43
|
-
operationalEpochKey1: Uint8Array | null;
|
|
44
|
-
groupSessionId1: number | null;
|
|
45
|
-
operationalEpochKey2: Uint8Array | null;
|
|
46
|
-
groupSessionId2: number | null;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
namespace OperationalGroupKeySet {
|
|
50
|
-
export const asTlvGroupSet = (
|
|
51
|
-
operationalGroupSet: OperationalGroupKeySet,
|
|
52
|
-
): TypeFromSchema<typeof GroupKeyManagement.TlvGroupKeySet> => {
|
|
53
|
-
const {
|
|
54
|
-
groupKeySetId,
|
|
55
|
-
epochKey0,
|
|
56
|
-
epochStartTime0,
|
|
57
|
-
epochKey1,
|
|
58
|
-
epochStartTime1,
|
|
59
|
-
epochKey2,
|
|
60
|
-
epochStartTime2,
|
|
61
|
-
groupKeySecurityPolicy,
|
|
62
|
-
groupKeyMulticastPolicy,
|
|
63
|
-
} = operationalGroupSet;
|
|
64
|
-
return {
|
|
65
|
-
groupKeySetId,
|
|
66
|
-
epochKey0,
|
|
67
|
-
epochStartTime0,
|
|
68
|
-
epochKey1,
|
|
69
|
-
epochStartTime1,
|
|
70
|
-
epochKey2,
|
|
71
|
-
epochStartTime2,
|
|
72
|
-
groupKeySecurityPolicy,
|
|
73
|
-
groupKeyMulticastPolicy,
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
40
|
export type ExposedFabricInformation = {
|
|
79
41
|
fabricIndex: FabricIndex;
|
|
80
42
|
fabricId: FabricId;
|
|
@@ -97,14 +59,13 @@ export class Fabric {
|
|
|
97
59
|
readonly operationalIdentityProtectionKey: Uint8Array;
|
|
98
60
|
readonly intermediateCACert: Uint8Array | undefined;
|
|
99
61
|
readonly operationalCert: Uint8Array;
|
|
100
|
-
|
|
101
62
|
readonly #keyPair: Key;
|
|
102
|
-
|
|
103
|
-
readonly #
|
|
104
|
-
|
|
63
|
+
readonly #sessions = new Set<Session>();
|
|
64
|
+
readonly #groupManager: FabricGroupsManager;
|
|
105
65
|
#label: string;
|
|
106
66
|
#removeCallbacks = new Array<() => MaybePromise<void>>();
|
|
107
67
|
#persistCallback: ((isUpdate?: boolean) => MaybePromise<void>) | undefined;
|
|
68
|
+
#storage?: StorageContext;
|
|
108
69
|
|
|
109
70
|
constructor(config: Fabric.Config) {
|
|
110
71
|
this.fabricIndex = config.fabricIndex;
|
|
@@ -120,8 +81,8 @@ export class Fabric {
|
|
|
120
81
|
this.intermediateCACert = config.intermediateCACert;
|
|
121
82
|
this.operationalCert = config.operationalCert;
|
|
122
83
|
this.#label = config.label;
|
|
123
|
-
|
|
124
84
|
this.#keyPair = PrivateKey(config.keyPair);
|
|
85
|
+
this.#groupManager = new FabricGroupsManager(this);
|
|
125
86
|
}
|
|
126
87
|
|
|
127
88
|
get config(): Fabric.Config {
|
|
@@ -158,6 +119,19 @@ export class Fabric {
|
|
|
158
119
|
await this.persist();
|
|
159
120
|
}
|
|
160
121
|
|
|
122
|
+
set storage(storage: StorageContext) {
|
|
123
|
+
this.#storage = storage;
|
|
124
|
+
this.#groupManager.storage = storage;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get storage(): StorageContext | undefined {
|
|
128
|
+
return this.#storage;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get groups() {
|
|
132
|
+
return this.#groupManager;
|
|
133
|
+
}
|
|
134
|
+
|
|
161
135
|
get publicKey() {
|
|
162
136
|
return this.#keyPair.publicKey;
|
|
163
137
|
}
|
|
@@ -190,20 +164,39 @@ export class Fabric {
|
|
|
190
164
|
);
|
|
191
165
|
}
|
|
192
166
|
|
|
193
|
-
|
|
167
|
+
#generateSalt(nodeId: NodeId, random: Uint8Array) {
|
|
194
168
|
const writer = new DataWriter(Endian.Little);
|
|
195
169
|
writer.writeByteArray(random);
|
|
196
170
|
writer.writeByteArray(this.rootPublicKey);
|
|
197
171
|
writer.writeUInt64(this.fabricId);
|
|
198
172
|
writer.writeUInt64(nodeId);
|
|
199
|
-
return
|
|
173
|
+
return writer.toByteArray();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Returns the destination IDs for a given nodeId, random value and optional groupId.
|
|
178
|
+
* When groupId is provided, it returns the time-wise valid operational keys for that groupId.
|
|
179
|
+
*/
|
|
180
|
+
async currentDestinationIdFor(nodeId: NodeId, random: Uint8Array) {
|
|
181
|
+
return await Crypto.hmac(this.groups.keySets.currentKeyForId(0).key, this.#generateSalt(nodeId, random));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Returns the destination IDs for a given nodeId, random value and optional groupId.
|
|
186
|
+
* When groupId is provided, it returns all operational keys for that groupId.
|
|
187
|
+
*/
|
|
188
|
+
async destinationIdsFor(nodeId: NodeId, random: Uint8Array) {
|
|
189
|
+
const salt = this.#generateSalt(nodeId, random);
|
|
190
|
+
// Check all keys of keyset 0 - typically it is only the IPK
|
|
191
|
+
const destinationIds = this.groups.keySets.allKeysForId(0).map(({ key }) => Crypto.hmac(key, salt));
|
|
192
|
+
return await Promise.all(destinationIds);
|
|
200
193
|
}
|
|
201
194
|
|
|
202
|
-
addSession(session:
|
|
195
|
+
addSession(session: Session) {
|
|
203
196
|
this.#sessions.add(session);
|
|
204
197
|
}
|
|
205
198
|
|
|
206
|
-
removeSession(session:
|
|
199
|
+
removeSession(session: Session) {
|
|
207
200
|
this.#sessions.delete(session);
|
|
208
201
|
}
|
|
209
202
|
|
|
@@ -236,39 +229,6 @@ export class Fabric {
|
|
|
236
229
|
return this.#persistCallback?.(isUpdate);
|
|
237
230
|
}
|
|
238
231
|
|
|
239
|
-
getGroupKeySet(groupKeySetId: number) {
|
|
240
|
-
if (groupKeySetId === 0) {
|
|
241
|
-
return OperationalGroupKeySet.asTlvGroupSet(this.getGroupSetForIpk());
|
|
242
|
-
}
|
|
243
|
-
// TODO add correct group handling later, right now only IPK exists
|
|
244
|
-
return undefined;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
private getGroupSetForIpk(): OperationalGroupKeySet {
|
|
248
|
-
return {
|
|
249
|
-
groupKeySetId: 0,
|
|
250
|
-
epochKey0: this.identityProtectionKey,
|
|
251
|
-
operationalEpochKey0: this.operationalIdentityProtectionKey,
|
|
252
|
-
epochStartTime0: 0, // or do we need to track Fabric creation date?
|
|
253
|
-
groupSessionId0: null,
|
|
254
|
-
epochKey1: null,
|
|
255
|
-
operationalEpochKey1: null,
|
|
256
|
-
epochStartTime1: null,
|
|
257
|
-
groupSessionId1: null,
|
|
258
|
-
epochKey2: null,
|
|
259
|
-
operationalEpochKey2: null,
|
|
260
|
-
epochStartTime2: null,
|
|
261
|
-
groupSessionId2: null,
|
|
262
|
-
groupKeySecurityPolicy: GroupKeyManagement.GroupKeySecurityPolicy.TrustFirst,
|
|
263
|
-
groupKeyMulticastPolicy: GroupKeyManagement.GroupKeyMulticastPolicy.PerGroupId,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
getAllGroupKeySets() {
|
|
268
|
-
// TODO add correct group handling later, right now only IPK exists
|
|
269
|
-
return [OperationalGroupKeySet.asTlvGroupSet(this.getGroupSetForIpk())];
|
|
270
|
-
}
|
|
271
|
-
|
|
272
232
|
get externalInformation(): ExposedFabricInformation {
|
|
273
233
|
return {
|
|
274
234
|
fabricIndex: this.fabricIndex,
|
|
@@ -283,6 +243,12 @@ export class Fabric {
|
|
|
283
243
|
addressOf(nodeId: NodeId) {
|
|
284
244
|
return PeerAddress({ fabricIndex: this.fabricIndex, nodeId });
|
|
285
245
|
}
|
|
246
|
+
|
|
247
|
+
groupAddressOf(groupId: GroupId) {
|
|
248
|
+
GroupId.assertGroupId(groupId);
|
|
249
|
+
|
|
250
|
+
return PeerAddress({ fabricIndex: this.fabricIndex, nodeId: NodeId.fromGroupId(groupId) });
|
|
251
|
+
}
|
|
286
252
|
}
|
|
287
253
|
|
|
288
254
|
export class FabricBuilder {
|
|
@@ -433,7 +399,7 @@ export class FabricBuilder {
|
|
|
433
399
|
throw new InternalError("operationalCert needs to be set");
|
|
434
400
|
|
|
435
401
|
this.#fabricIndex = fabricIndex;
|
|
436
|
-
const saltWriter = new DataWriter(
|
|
402
|
+
const saltWriter = new DataWriter();
|
|
437
403
|
saltWriter.writeUInt64(this.#fabricId);
|
|
438
404
|
const operationalId = await Crypto.hkdf(
|
|
439
405
|
this.#rootPublicKey.slice(1),
|