@matter/protocol 0.14.1-alpha.0-20250605-9fc134af0 → 0.14.1-alpha.0-20250607-a93593303

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.
Files changed (312) hide show
  1. package/dist/cjs/action/server/AccessControl.d.ts +5 -7
  2. package/dist/cjs/action/server/AccessControl.d.ts.map +1 -1
  3. package/dist/cjs/action/server/AccessControl.js.map +1 -1
  4. package/dist/cjs/action/server/AttributeWriteResponse.d.ts.map +1 -1
  5. package/dist/cjs/action/server/AttributeWriteResponse.js +23 -0
  6. package/dist/cjs/action/server/AttributeWriteResponse.js.map +1 -1
  7. package/dist/cjs/action/server/CommandInvokeResponse.d.ts.map +1 -1
  8. package/dist/cjs/action/server/CommandInvokeResponse.js +24 -1
  9. package/dist/cjs/action/server/CommandInvokeResponse.js.map +1 -1
  10. package/dist/cjs/action/server/DataResponse.d.ts +1 -1
  11. package/dist/cjs/action/server/DataResponse.d.ts.map +1 -1
  12. package/dist/cjs/action/server/Subject.d.ts +25 -0
  13. package/dist/cjs/action/server/Subject.d.ts.map +1 -0
  14. package/dist/cjs/action/server/Subject.js +54 -0
  15. package/dist/cjs/action/server/Subject.js.map +6 -0
  16. package/dist/cjs/action/server/index.d.ts +1 -0
  17. package/dist/cjs/action/server/index.d.ts.map +1 -1
  18. package/dist/cjs/action/server/index.js +1 -0
  19. package/dist/cjs/action/server/index.js.map +1 -1
  20. package/dist/cjs/certificate/DeviceCertification.d.ts +2 -2
  21. package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
  22. package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
  23. package/dist/cjs/cluster/client/AttributeClient.d.ts +3 -3
  24. package/dist/cjs/cluster/client/AttributeClient.d.ts.map +1 -1
  25. package/dist/cjs/cluster/client/AttributeClient.js +14 -2
  26. package/dist/cjs/cluster/client/AttributeClient.js.map +1 -1
  27. package/dist/cjs/cluster/client/ClusterClient.d.ts +3 -2
  28. package/dist/cjs/cluster/client/ClusterClient.d.ts.map +1 -1
  29. package/dist/cjs/cluster/client/ClusterClient.js +66 -1
  30. package/dist/cjs/cluster/client/ClusterClient.js.map +1 -1
  31. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts +36 -8
  32. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  33. package/dist/cjs/cluster/client/EventClient.d.ts +3 -3
  34. package/dist/cjs/cluster/client/EventClient.d.ts.map +1 -1
  35. package/dist/cjs/cluster/client/EventClient.js +7 -0
  36. package/dist/cjs/cluster/client/EventClient.js.map +1 -1
  37. package/dist/cjs/codec/MessageCodec.d.ts.map +1 -1
  38. package/dist/cjs/codec/MessageCodec.js +31 -6
  39. package/dist/cjs/codec/MessageCodec.js.map +1 -1
  40. package/dist/cjs/fabric/Fabric.d.ts +20 -30
  41. package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
  42. package/dist/cjs/fabric/Fabric.js +38 -62
  43. package/dist/cjs/fabric/Fabric.js.map +2 -2
  44. package/dist/cjs/fabric/FabricManager.d.ts.map +1 -1
  45. package/dist/cjs/fabric/FabricManager.js +10 -4
  46. package/dist/cjs/fabric/FabricManager.js.map +1 -1
  47. package/dist/cjs/groups/FabricGroupsManager.d.ts +46 -0
  48. package/dist/cjs/groups/FabricGroupsManager.d.ts.map +1 -0
  49. package/dist/cjs/groups/FabricGroupsManager.js +155 -0
  50. package/dist/cjs/groups/FabricGroupsManager.js.map +6 -0
  51. package/dist/cjs/groups/Groups.d.ts +34 -0
  52. package/dist/cjs/groups/Groups.d.ts.map +1 -0
  53. package/dist/cjs/groups/Groups.js +89 -0
  54. package/dist/cjs/groups/Groups.js.map +6 -0
  55. package/dist/cjs/groups/KeySets.d.ts +64 -0
  56. package/dist/cjs/groups/KeySets.d.ts.map +1 -0
  57. package/dist/cjs/groups/KeySets.js +179 -0
  58. package/dist/cjs/groups/KeySets.js.map +6 -0
  59. package/dist/cjs/groups/MessagingState.d.ts +24 -0
  60. package/dist/cjs/groups/MessagingState.d.ts.map +1 -0
  61. package/dist/cjs/groups/MessagingState.js +91 -0
  62. package/dist/cjs/groups/MessagingState.js.map +6 -0
  63. package/dist/cjs/groups/index.d.ts +8 -0
  64. package/dist/cjs/groups/index.d.ts.map +1 -0
  65. package/dist/cjs/groups/index.js +25 -0
  66. package/dist/cjs/groups/index.js.map +6 -0
  67. package/dist/cjs/index.d.ts +1 -0
  68. package/dist/cjs/index.d.ts.map +1 -1
  69. package/dist/cjs/index.js +1 -0
  70. package/dist/cjs/index.js.map +1 -1
  71. package/dist/cjs/interaction/AccessControlManager.d.ts +4 -13
  72. package/dist/cjs/interaction/AccessControlManager.d.ts.map +1 -1
  73. package/dist/cjs/interaction/AccessControlManager.js +38 -47
  74. package/dist/cjs/interaction/AccessControlManager.js.map +1 -1
  75. package/dist/cjs/interaction/InteractionClient.d.ts +5 -4
  76. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  77. package/dist/cjs/interaction/InteractionClient.js +53 -3
  78. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  79. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  80. package/dist/cjs/interaction/InteractionMessenger.js +15 -0
  81. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  82. package/dist/cjs/interaction/Subscription.d.ts +3 -3
  83. package/dist/cjs/interaction/Subscription.d.ts.map +1 -1
  84. package/dist/cjs/interaction/Subscription.js.map +1 -1
  85. package/dist/cjs/peer/PeerAddress.d.ts +1 -0
  86. package/dist/cjs/peer/PeerAddress.d.ts.map +1 -1
  87. package/dist/cjs/peer/PeerAddress.js +5 -0
  88. package/dist/cjs/peer/PeerAddress.js.map +1 -1
  89. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  90. package/dist/cjs/peer/PeerSet.js +31 -2
  91. package/dist/cjs/peer/PeerSet.js.map +1 -1
  92. package/dist/cjs/protocol/ChannelManager.d.ts.map +1 -1
  93. package/dist/cjs/protocol/ChannelManager.js +7 -8
  94. package/dist/cjs/protocol/ChannelManager.js.map +1 -1
  95. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  96. package/dist/cjs/protocol/ExchangeManager.js +39 -25
  97. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  98. package/dist/cjs/protocol/MessageExchange.d.ts +1 -1
  99. package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
  100. package/dist/cjs/protocol/MessageExchange.js +32 -4
  101. package/dist/cjs/protocol/MessageExchange.js.map +1 -1
  102. package/dist/cjs/protocol/MessageReceptionState.d.ts +1 -1
  103. package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -1
  104. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  105. package/dist/cjs/session/GroupSession.d.ts +56 -0
  106. package/dist/cjs/session/GroupSession.d.ts.map +1 -0
  107. package/dist/cjs/session/GroupSession.js +188 -0
  108. package/dist/cjs/session/GroupSession.js.map +6 -0
  109. package/dist/cjs/session/InsecureSession.d.ts +2 -1
  110. package/dist/cjs/session/InsecureSession.d.ts.map +1 -1
  111. package/dist/cjs/session/InsecureSession.js +3 -2
  112. package/dist/cjs/session/InsecureSession.js.map +1 -1
  113. package/dist/cjs/session/NodeSession.d.ts +88 -0
  114. package/dist/cjs/session/NodeSession.d.ts.map +1 -0
  115. package/dist/cjs/session/NodeSession.js +318 -0
  116. package/dist/cjs/session/NodeSession.js.map +6 -0
  117. package/dist/cjs/session/SecureSession.d.ts +10 -75
  118. package/dist/cjs/session/SecureSession.d.ts.map +1 -1
  119. package/dist/cjs/session/SecureSession.js +9 -280
  120. package/dist/cjs/session/SecureSession.js.map +2 -2
  121. package/dist/cjs/session/Session.d.ts +6 -5
  122. package/dist/cjs/session/Session.d.ts.map +1 -1
  123. package/dist/cjs/session/Session.js +11 -1
  124. package/dist/cjs/session/Session.js.map +1 -1
  125. package/dist/cjs/session/SessionManager.d.ts +27 -9
  126. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  127. package/dist/cjs/session/SessionManager.js +83 -5
  128. package/dist/cjs/session/SessionManager.js.map +2 -2
  129. package/dist/cjs/session/case/CaseClient.d.ts +1 -1
  130. package/dist/cjs/session/case/CaseClient.js +2 -2
  131. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  132. package/dist/cjs/session/index.d.ts +2 -0
  133. package/dist/cjs/session/index.d.ts.map +1 -1
  134. package/dist/cjs/session/index.js +2 -0
  135. package/dist/cjs/session/index.js.map +1 -1
  136. package/dist/cjs/session/pase/PaseClient.d.ts +1 -1
  137. package/dist/esm/action/server/AccessControl.d.ts +5 -7
  138. package/dist/esm/action/server/AccessControl.d.ts.map +1 -1
  139. package/dist/esm/action/server/AccessControl.js.map +1 -1
  140. package/dist/esm/action/server/AttributeWriteResponse.d.ts.map +1 -1
  141. package/dist/esm/action/server/AttributeWriteResponse.js +23 -0
  142. package/dist/esm/action/server/AttributeWriteResponse.js.map +1 -1
  143. package/dist/esm/action/server/CommandInvokeResponse.d.ts.map +1 -1
  144. package/dist/esm/action/server/CommandInvokeResponse.js +24 -1
  145. package/dist/esm/action/server/CommandInvokeResponse.js.map +1 -1
  146. package/dist/esm/action/server/DataResponse.d.ts +1 -1
  147. package/dist/esm/action/server/DataResponse.d.ts.map +1 -1
  148. package/dist/esm/action/server/Subject.d.ts +25 -0
  149. package/dist/esm/action/server/Subject.d.ts.map +1 -0
  150. package/dist/esm/action/server/Subject.js +34 -0
  151. package/dist/esm/action/server/Subject.js.map +6 -0
  152. package/dist/esm/action/server/index.d.ts +1 -0
  153. package/dist/esm/action/server/index.d.ts.map +1 -1
  154. package/dist/esm/action/server/index.js +1 -0
  155. package/dist/esm/action/server/index.js.map +1 -1
  156. package/dist/esm/certificate/DeviceCertification.d.ts +2 -2
  157. package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
  158. package/dist/esm/certificate/DeviceCertification.js.map +1 -1
  159. package/dist/esm/cluster/client/AttributeClient.d.ts +3 -3
  160. package/dist/esm/cluster/client/AttributeClient.d.ts.map +1 -1
  161. package/dist/esm/cluster/client/AttributeClient.js +13 -1
  162. package/dist/esm/cluster/client/AttributeClient.js.map +1 -1
  163. package/dist/esm/cluster/client/ClusterClient.d.ts +3 -2
  164. package/dist/esm/cluster/client/ClusterClient.d.ts.map +1 -1
  165. package/dist/esm/cluster/client/ClusterClient.js +67 -2
  166. package/dist/esm/cluster/client/ClusterClient.js.map +1 -1
  167. package/dist/esm/cluster/client/ClusterClientTypes.d.ts +36 -8
  168. package/dist/esm/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  169. package/dist/esm/cluster/client/EventClient.d.ts +3 -3
  170. package/dist/esm/cluster/client/EventClient.d.ts.map +1 -1
  171. package/dist/esm/cluster/client/EventClient.js +7 -0
  172. package/dist/esm/cluster/client/EventClient.js.map +1 -1
  173. package/dist/esm/codec/MessageCodec.d.ts.map +1 -1
  174. package/dist/esm/codec/MessageCodec.js +41 -7
  175. package/dist/esm/codec/MessageCodec.js.map +1 -1
  176. package/dist/esm/fabric/Fabric.d.ts +20 -30
  177. package/dist/esm/fabric/Fabric.d.ts.map +1 -1
  178. package/dist/esm/fabric/Fabric.js +38 -62
  179. package/dist/esm/fabric/Fabric.js.map +2 -2
  180. package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
  181. package/dist/esm/fabric/FabricManager.js +10 -4
  182. package/dist/esm/fabric/FabricManager.js.map +1 -1
  183. package/dist/esm/groups/FabricGroupsManager.d.ts +46 -0
  184. package/dist/esm/groups/FabricGroupsManager.d.ts.map +1 -0
  185. package/dist/esm/groups/FabricGroupsManager.js +135 -0
  186. package/dist/esm/groups/FabricGroupsManager.js.map +6 -0
  187. package/dist/esm/groups/Groups.d.ts +34 -0
  188. package/dist/esm/groups/Groups.d.ts.map +1 -0
  189. package/dist/esm/groups/Groups.js +69 -0
  190. package/dist/esm/groups/Groups.js.map +6 -0
  191. package/dist/esm/groups/KeySets.d.ts +64 -0
  192. package/dist/esm/groups/KeySets.d.ts.map +1 -0
  193. package/dist/esm/groups/KeySets.js +159 -0
  194. package/dist/esm/groups/KeySets.js.map +6 -0
  195. package/dist/esm/groups/MessagingState.d.ts +24 -0
  196. package/dist/esm/groups/MessagingState.d.ts.map +1 -0
  197. package/dist/esm/groups/MessagingState.js +71 -0
  198. package/dist/esm/groups/MessagingState.js.map +6 -0
  199. package/dist/esm/groups/index.d.ts +8 -0
  200. package/dist/esm/groups/index.d.ts.map +1 -0
  201. package/dist/esm/groups/index.js +8 -0
  202. package/dist/esm/groups/index.js.map +6 -0
  203. package/dist/esm/index.d.ts +1 -0
  204. package/dist/esm/index.d.ts.map +1 -1
  205. package/dist/esm/index.js +1 -0
  206. package/dist/esm/index.js.map +1 -1
  207. package/dist/esm/interaction/AccessControlManager.d.ts +4 -13
  208. package/dist/esm/interaction/AccessControlManager.d.ts.map +1 -1
  209. package/dist/esm/interaction/AccessControlManager.js +39 -48
  210. package/dist/esm/interaction/AccessControlManager.js.map +1 -1
  211. package/dist/esm/interaction/InteractionClient.d.ts +5 -4
  212. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  213. package/dist/esm/interaction/InteractionClient.js +54 -4
  214. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  215. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  216. package/dist/esm/interaction/InteractionMessenger.js +15 -0
  217. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  218. package/dist/esm/interaction/Subscription.d.ts +3 -3
  219. package/dist/esm/interaction/Subscription.d.ts.map +1 -1
  220. package/dist/esm/interaction/Subscription.js.map +1 -1
  221. package/dist/esm/peer/PeerAddress.d.ts +1 -0
  222. package/dist/esm/peer/PeerAddress.d.ts.map +1 -1
  223. package/dist/esm/peer/PeerAddress.js +5 -0
  224. package/dist/esm/peer/PeerAddress.js.map +1 -1
  225. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  226. package/dist/esm/peer/PeerSet.js +33 -3
  227. package/dist/esm/peer/PeerSet.js.map +1 -1
  228. package/dist/esm/protocol/ChannelManager.d.ts.map +1 -1
  229. package/dist/esm/protocol/ChannelManager.js +7 -8
  230. package/dist/esm/protocol/ChannelManager.js.map +1 -1
  231. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  232. package/dist/esm/protocol/ExchangeManager.js +41 -27
  233. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  234. package/dist/esm/protocol/MessageExchange.d.ts +1 -1
  235. package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
  236. package/dist/esm/protocol/MessageExchange.js +39 -5
  237. package/dist/esm/protocol/MessageExchange.js.map +1 -1
  238. package/dist/esm/protocol/MessageReceptionState.d.ts +1 -1
  239. package/dist/esm/securechannel/SecureChannelProtocol.js +2 -2
  240. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  241. package/dist/esm/session/GroupSession.d.ts +56 -0
  242. package/dist/esm/session/GroupSession.d.ts.map +1 -0
  243. package/dist/esm/session/GroupSession.js +177 -0
  244. package/dist/esm/session/GroupSession.js.map +6 -0
  245. package/dist/esm/session/InsecureSession.d.ts +2 -1
  246. package/dist/esm/session/InsecureSession.d.ts.map +1 -1
  247. package/dist/esm/session/InsecureSession.js +3 -2
  248. package/dist/esm/session/InsecureSession.js.map +1 -1
  249. package/dist/esm/session/NodeSession.d.ts +88 -0
  250. package/dist/esm/session/NodeSession.d.ts.map +1 -0
  251. package/dist/esm/session/NodeSession.js +298 -0
  252. package/dist/esm/session/NodeSession.js.map +6 -0
  253. package/dist/esm/session/SecureSession.d.ts +10 -75
  254. package/dist/esm/session/SecureSession.d.ts.map +1 -1
  255. package/dist/esm/session/SecureSession.js +10 -291
  256. package/dist/esm/session/SecureSession.js.map +2 -2
  257. package/dist/esm/session/Session.d.ts +6 -5
  258. package/dist/esm/session/Session.d.ts.map +1 -1
  259. package/dist/esm/session/Session.js +12 -2
  260. package/dist/esm/session/Session.js.map +1 -1
  261. package/dist/esm/session/SessionManager.d.ts +27 -9
  262. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  263. package/dist/esm/session/SessionManager.js +84 -6
  264. package/dist/esm/session/SessionManager.js.map +1 -1
  265. package/dist/esm/session/case/CaseClient.d.ts +1 -1
  266. package/dist/esm/session/case/CaseClient.js +2 -2
  267. package/dist/esm/session/case/CaseClient.js.map +1 -1
  268. package/dist/esm/session/index.d.ts +2 -0
  269. package/dist/esm/session/index.d.ts.map +1 -1
  270. package/dist/esm/session/index.js +2 -0
  271. package/dist/esm/session/index.js.map +1 -1
  272. package/dist/esm/session/pase/PaseClient.d.ts +1 -1
  273. package/package.json +6 -6
  274. package/src/action/server/AccessControl.ts +4 -7
  275. package/src/action/server/AttributeWriteResponse.ts +29 -7
  276. package/src/action/server/CommandInvokeResponse.ts +28 -7
  277. package/src/action/server/DataResponse.ts +1 -1
  278. package/src/action/server/Subject.ts +45 -0
  279. package/src/action/server/index.ts +1 -0
  280. package/src/certificate/DeviceCertification.ts +2 -2
  281. package/src/cluster/client/AttributeClient.ts +15 -3
  282. package/src/cluster/client/ClusterClient.ts +97 -4
  283. package/src/cluster/client/ClusterClientTypes.ts +45 -9
  284. package/src/cluster/client/EventClient.ts +9 -2
  285. package/src/codec/MessageCodec.ts +49 -8
  286. package/src/fabric/Fabric.ts +51 -85
  287. package/src/fabric/FabricManager.ts +11 -4
  288. package/src/groups/FabricGroupsManager.ts +164 -0
  289. package/src/groups/Groups.ts +81 -0
  290. package/src/groups/KeySets.ts +194 -0
  291. package/src/groups/MessagingState.ts +76 -0
  292. package/src/groups/index.ts +8 -0
  293. package/src/index.ts +1 -0
  294. package/src/interaction/AccessControlManager.ts +49 -81
  295. package/src/interaction/InteractionClient.ts +66 -6
  296. package/src/interaction/InteractionMessenger.ts +15 -0
  297. package/src/interaction/Subscription.ts +3 -3
  298. package/src/peer/PeerAddress.ts +4 -0
  299. package/src/peer/PeerSet.ts +39 -4
  300. package/src/protocol/ChannelManager.ts +7 -9
  301. package/src/protocol/ExchangeManager.ts +51 -35
  302. package/src/protocol/MessageExchange.ts +42 -7
  303. package/src/protocol/MessageReceptionState.ts +2 -2
  304. package/src/securechannel/SecureChannelProtocol.ts +2 -2
  305. package/src/session/GroupSession.ts +223 -0
  306. package/src/session/InsecureSession.ts +3 -2
  307. package/src/session/NodeSession.ts +367 -0
  308. package/src/session/SecureSession.ts +14 -363
  309. package/src/session/Session.ts +17 -6
  310. package/src/session/SessionManager.ts +94 -14
  311. package/src/session/case/CaseClient.ts +2 -2
  312. package/src/session/index.ts +2 -3
@@ -0,0 +1,194 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import type { GroupKeyManagement } from "#clusters/group-key-management";
8
+ import { BasicSet, Bytes, Crypto, DataReader, ImplementationError, MatterFlowError, Time } from "#general";
9
+
10
+ export const GROUP_KEY_INFO = Bytes.fromString("GroupKeyHash");
11
+
12
+ export class KeySets<T extends OperationalKeySet> extends BasicSet<T> {
13
+ /** Operational enhanced structure for fast access based on the group session id. */
14
+ readonly #sessions = new Map<number, { keySetId: number; key: Uint8Array }[]>();
15
+
16
+ get sessions() {
17
+ return this.#sessions;
18
+ }
19
+
20
+ override add(item: T): void {
21
+ this.delete("groupKeySetId", item.groupKeySetId); // Remove any existing item with the same groupKeySetId
22
+ super.add(item);
23
+ this.#updateSessions();
24
+ }
25
+
26
+ override delete<F extends keyof T>(itemOrField: T | F, value?: T[F]): boolean {
27
+ const deleted = super.delete(itemOrField as any, value as any);
28
+ if (deleted) {
29
+ this.#updateSessions();
30
+ }
31
+ return deleted;
32
+ }
33
+
34
+ forId(groupKeySetId: number): OperationalKeySet | undefined {
35
+ return this.get("groupKeySetId", groupKeySetId);
36
+ }
37
+
38
+ /**
39
+ * Return an operative list of operational keys, start time and their session IDs for a specified
40
+ * group key set id. This is mainly used for receiving messages.
41
+ */
42
+ allKeysForId(keySetId: number) {
43
+ const groupKeySet = this.forId(keySetId);
44
+ if (groupKeySet === undefined) {
45
+ throw new MatterFlowError(`GroupKeySet for groupKeySet ${keySetId} not found.`);
46
+ }
47
+ const operationalKeys = Array<{ key: Uint8Array; sessionId?: number; startTime: number | bigint }>();
48
+ const {
49
+ operationalEpochKey0,
50
+ groupSessionId0,
51
+ epochStartTime0,
52
+ operationalEpochKey1,
53
+ groupSessionId1,
54
+ epochStartTime1,
55
+ operationalEpochKey2,
56
+ groupSessionId2,
57
+ epochStartTime2,
58
+ } = groupKeySet;
59
+ if (operationalEpochKey0 === null || epochStartTime0 === null || (keySetId !== 0 && groupSessionId0 === null)) {
60
+ // should never happen, but just in case
61
+ throw new MatterFlowError(`EpochKey0 for groupKeySet ${keySetId} not found.`);
62
+ }
63
+ operationalKeys.push({
64
+ key: operationalEpochKey0,
65
+ sessionId: groupSessionId0 !== null ? groupSessionId0 : undefined,
66
+ startTime: epochStartTime0,
67
+ });
68
+ if (operationalEpochKey1 !== null && groupSessionId1 !== null && epochStartTime1 !== null) {
69
+ operationalKeys.push({ key: operationalEpochKey1, sessionId: groupSessionId1, startTime: epochStartTime1 });
70
+ }
71
+ if (operationalEpochKey2 !== null && groupSessionId2 !== null && epochStartTime2 !== null) {
72
+ operationalKeys.push({ key: operationalEpochKey2, sessionId: groupSessionId2, startTime: epochStartTime2 });
73
+ }
74
+ return operationalKeys;
75
+ }
76
+
77
+ /**
78
+ * Returns the current operational group key for a given group KeySet Id and returns the keys, start time and
79
+ * their session IDs. This is mainly used for sending messages.
80
+ */
81
+ currentKeyForId(keySetId: number) {
82
+ const operationalKeys = this.allKeysForId(keySetId);
83
+ if (operationalKeys.length === 0) {
84
+ throw new MatterFlowError(`No operational keys found for groupKeySet ${keySetId}.`);
85
+ }
86
+ if (keySetId === 0) {
87
+ // Groups: For the generation of the Destination Identifier, the originator SHALL use the operational group key with
88
+ // the second newest EpochStartTime, if one exists, otherwise it SHALL use the single operational group key available.
89
+ // @see {@link MatterSpecification.v14.Core} § 4.14.2.6.
90
+ if (operationalKeys.length > 2) {
91
+ return operationalKeys[1];
92
+ }
93
+ return operationalKeys[0];
94
+ } else {
95
+ // Nodes sending group messages SHALL use operational group keys that are derived from the current
96
+ // epoch key (specifically, the epoch key with the latest start time that is not in the future).
97
+ // TODO Nodes that cannot reliably keep track of time calculate the current epoch key as described in
98
+ // Section 4.17.3.4, “Epoch Key Rotation without Time Synchronization”.
99
+ const now = Time.nowUs();
100
+ const relevantKeys = operationalKeys.filter(({ startTime }) => startTime <= now);
101
+ if (relevantKeys.length === 0) {
102
+ throw new ImplementationError(
103
+ `No operational keys found for groupKeySet ${keySetId} that are not in the future.`,
104
+ );
105
+ }
106
+ return relevantKeys[operationalKeys.length - 1];
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Returns the group key set for a given group key set id in the official data format from the Group key Management
112
+ * cluster.
113
+ */
114
+ asGroupKeySet(groupKeySetId: number) {
115
+ const groupKeySet = this.forId(groupKeySetId);
116
+ if (groupKeySet === undefined) {
117
+ return undefined;
118
+ }
119
+
120
+ const {
121
+ epochKey0,
122
+ epochStartTime0,
123
+ epochKey1,
124
+ epochStartTime1,
125
+ epochKey2,
126
+ epochStartTime2,
127
+ groupKeySecurityPolicy,
128
+ groupKeyMulticastPolicy,
129
+ } = groupKeySet;
130
+ return {
131
+ groupKeySetId,
132
+ epochKey0,
133
+ epochStartTime0,
134
+ epochKey1,
135
+ epochStartTime1,
136
+ epochKey2,
137
+ epochStartTime2,
138
+ groupKeySecurityPolicy,
139
+ groupKeyMulticastPolicy,
140
+ };
141
+ }
142
+
143
+ /** Calculates a group session id based on the operational group key. */
144
+ async sessionIdFromKey(operationalGroupKey: Uint8Array) {
145
+ // GroupKeyHash is an array of 2 bytes (16 bits) per Crypto_KDF
146
+ const groupKeyHash = await Crypto.hkdf(operationalGroupKey, new Uint8Array(), GROUP_KEY_INFO, 2);
147
+
148
+ // GroupSessionId is computed by considering the GroupKeyHash as a Big-Endian value. GroupSessionId is a scalar.
149
+ // Its use in fields within messages may cause a re-serialization into a different byte order than the one used
150
+ // for initial generation.
151
+ return new DataReader(groupKeyHash).readUInt16();
152
+ }
153
+
154
+ /**
155
+ * Updates the group session map based on the current group key sets.
156
+ * This is used to quickly find the operational keys by their group session id.
157
+ */
158
+ #updateSessions() {
159
+ this.#sessions.clear();
160
+ for (const [id, keySet] of this.mapOf("groupKeySetId").entries()) {
161
+ if (id === 0) {
162
+ // Skip the default group key set (0), as it is not used for operational keys
163
+ continue;
164
+ }
165
+ if (keySet.groupSessionId0 !== null) {
166
+ const list = this.#sessions.get(keySet.groupSessionId0) ?? [];
167
+ list.push({ key: keySet.operationalEpochKey0, keySetId: id });
168
+ this.#sessions.set(keySet.groupSessionId0, list);
169
+ }
170
+ if (keySet.groupSessionId1 !== null && keySet.operationalEpochKey1 !== null) {
171
+ const list = this.#sessions.get(keySet.groupSessionId1) ?? [];
172
+ list.push({ key: keySet.operationalEpochKey1, keySetId: id });
173
+ this.#sessions.set(keySet.groupSessionId1, list);
174
+ }
175
+ if (keySet.groupSessionId2 !== null && keySet.operationalEpochKey2 !== null) {
176
+ const list = this.#sessions.get(keySet.groupSessionId2) ?? [];
177
+ list.push({ key: keySet.operationalEpochKey2, keySetId: id });
178
+ this.#sessions.set(keySet.groupSessionId2, list);
179
+ }
180
+ }
181
+ }
182
+ }
183
+
184
+ export type GroupKeySet = GroupKeyManagement.GroupKeySet;
185
+
186
+ /** Enhanced structure of GroupKeySet to include operational data for easier operational processing. */
187
+ export type OperationalKeySet = GroupKeySet & {
188
+ operationalEpochKey0: Uint8Array;
189
+ groupSessionId0: number | null;
190
+ operationalEpochKey1: Uint8Array | null;
191
+ groupSessionId1: number | null;
192
+ operationalEpochKey2: Uint8Array | null;
193
+ groupSessionId2: number | null;
194
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Bytes, ImplementationError, InternalError, StorageContext } from "#general";
7
+ import { PersistedMessageCounter } from "#protocol/MessageCounter.js";
8
+ import { MessageReceptionStateEncryptedWithRollover } from "#protocol/MessageReceptionState.js";
9
+ import { NodeId } from "#types";
10
+
11
+ export class MessagingState {
12
+ /**
13
+ * Message counter for sending data messages to a group per Operational key. No need to scope to a source node
14
+ * because we are the sending node
15
+ * TODO: For management: Make sure to start rotating the key early enough that a former counter-value is not used
16
+ * again for the same key.
17
+ */
18
+ readonly #groupDataCounters = new Map<string, PersistedMessageCounter>();
19
+
20
+ /** Message reception state for data messages per Operational key and source node. */
21
+ readonly #messageDataReceptionState = new Map<string, Map<NodeId, MessageReceptionStateEncryptedWithRollover>>();
22
+ #storage?: StorageContext;
23
+
24
+ constructor(storage?: StorageContext) {
25
+ if (storage !== undefined) {
26
+ this.#storage = storage;
27
+ }
28
+ }
29
+
30
+ set storage(storage: StorageContext) {
31
+ if (this.#storage !== undefined) {
32
+ throw new InternalError("Storage context can only be set once.");
33
+ }
34
+ this.#storage = storage;
35
+ }
36
+
37
+ /**
38
+ * Return the message counter for sending messages to a group with the given operational key.
39
+ */
40
+ counterFor(operationalKey: Uint8Array) {
41
+ if (!this.#storage) {
42
+ throw new ImplementationError("Group session cannot be created without storage context.");
43
+ }
44
+ const operationalKeyHex = Bytes.toHex(operationalKey);
45
+ let counter = this.#groupDataCounters.get(operationalKeyHex);
46
+ if (counter === undefined) {
47
+ counter = new PersistedMessageCounter(this.#storage, `${operationalKeyHex}-data`);
48
+ this.#groupDataCounters.set(operationalKeyHex, counter);
49
+ }
50
+ return counter;
51
+ }
52
+
53
+ async removeCounter(key: Uint8Array, forDelete = false) {
54
+ const operationalKeyHex = Bytes.toHex(key);
55
+ this.#groupDataCounters.delete(operationalKeyHex);
56
+ if (forDelete) {
57
+ // If we are deleting the group key set, also delete the persisted counter values
58
+ await this.#storage?.delete(`${operationalKeyHex}-data`);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Returns the message reception state for a given source node id and operational key.
64
+ */
65
+ receptionStateFor(sourceNodeId: NodeId, operationalKey: Uint8Array) {
66
+ const operationalKeyHex = Bytes.toHex(operationalKey);
67
+ let receptionState = this.#messageDataReceptionState.get(operationalKeyHex)?.get(sourceNodeId);
68
+ if (receptionState === undefined) {
69
+ receptionState = new MessageReceptionStateEncryptedWithRollover();
70
+ const keyMap = this.#messageDataReceptionState.get(operationalKeyHex) ?? new Map();
71
+ keyMap.set(sourceNodeId, receptionState);
72
+ this.#messageDataReceptionState.set(operationalKeyHex, keyMap);
73
+ }
74
+ return receptionState;
75
+ }
76
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ export * from "./FabricGroupsManager.js";
8
+ export * from "./KeySets.js";
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./codec/index.js";
12
12
  export * from "./common/index.js";
13
13
  export * from "./events/index.js";
14
14
  export * from "./fabric/index.js";
15
+ export * from "./groups/index.js";
15
16
  export * from "./interaction/index.js";
16
17
  export * from "./mdns/index.js";
17
18
  export * from "./peer/index.js";
@@ -3,8 +3,9 @@
3
3
  * Copyright 2022-2023 Project CHIP Authors
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import { Subject } from "#action/server/Subject.js";
6
7
  import { AccessControl } from "#clusters/access-control";
7
- import { Logger, MatterFlowError, toHex } from "#general";
8
+ import { MatterFlowError } from "#general";
8
9
  import { AccessLevel } from "#model";
9
10
  import {
10
11
  CaseAuthenticatedTag,
@@ -15,11 +16,9 @@ import {
15
16
  NodeId,
16
17
  StatusCode,
17
18
  StatusResponseError,
19
+ SubjectId,
18
20
  } from "#types";
19
- import { Fabric } from "../fabric/Fabric.js";
20
- import { SecureSession } from "../session/SecureSession.js";
21
-
22
- const logger = Logger.get("AccessControlManager");
21
+ import { AccessControl as AccessControlContext } from "../action/server/AccessControl.js";
23
22
 
24
23
  export type AclEntry = Omit<AccessControl.AccessControlEntry, "privilege"> & {
25
24
  privilege: AccessLevel;
@@ -49,7 +48,7 @@ enum AuthModeNone {
49
48
  export type IncomingSubjectDescriptor = {
50
49
  isCommissioning: boolean;
51
50
  authMode: AccessControl.AccessControlEntryAuthMode | AuthModeNone;
52
- subjects: NodeId[];
51
+ subjects: SubjectId[];
53
52
  fabricIndex: FabricIndex;
54
53
  };
55
54
 
@@ -98,22 +97,24 @@ export class AccessControlManager {
98
97
  /**
99
98
  * Get the Access Control List for a given fabric.
100
99
  */
101
- #getAccessControlEntriesForFabric(fabric: Fabric): AclList {
102
- return this.#aclList.filter(entry => entry.fabricIndex === fabric.fabricIndex);
100
+ #getAccessControlEntriesForFabric(fabricIndex: FabricIndex): AclList {
101
+ return this.#aclList.filter(entry => entry.fabricIndex === fabricIndex);
103
102
  }
104
103
 
105
104
  /**
106
105
  * Subjects must match exactly, or both are CAT with matching CAT ID and acceptable CAT version
107
106
  */
108
- #subjectMatches(aclSubject: NodeId, isdSubject: NodeId): boolean {
109
- if (aclSubject === isdSubject) {
107
+ #subjectMatches(aclSubject: SubjectId, isdSubject: SubjectId): boolean {
108
+ if (BigInt(aclSubject) === BigInt(isdSubject)) {
110
109
  return true;
111
110
  }
112
- if (!NodeId.isCaseAuthenticatedTag(aclSubject) || !NodeId.isCaseAuthenticatedTag(isdSubject)) {
111
+ const aclNode = NodeId(aclSubject);
112
+ const isdNode = NodeId(isdSubject);
113
+ if (!NodeId.isCaseAuthenticatedTag(aclNode) || !NodeId.isCaseAuthenticatedTag(isdNode)) {
113
114
  return false;
114
115
  }
115
- const aclSubjectCat = NodeId.extractAsCaseAuthenticatedTag(aclSubject);
116
- const isdSubjectCat = NodeId.extractAsCaseAuthenticatedTag(isdSubject);
116
+ const aclSubjectCat = NodeId.extractAsCaseAuthenticatedTag(aclNode);
117
+ const isdSubjectCat = NodeId.extractAsCaseAuthenticatedTag(isdNode);
117
118
  return (
118
119
  CaseAuthenticatedTag.getIdentifyValue(aclSubjectCat) ===
119
120
  CaseAuthenticatedTag.getIdentifyValue(isdSubjectCat) &&
@@ -149,40 +150,16 @@ export class AccessControlManager {
149
150
  }
150
151
 
151
152
  /**
152
- * Check if the given ACL entry is allowed to be used for the given subject descriptor, endpoint, and cluster ID.
153
+ * Determines the granted privileges for the given session, endpoint, and cluster ID and returns them.
153
154
  */
154
- allowsPrivilege(
155
- session: SecureSession,
155
+ getGrantedPrivileges(
156
+ context: AccessControlContext.Session,
156
157
  endpoint: AclEndpointContext,
157
158
  clusterId: ClusterId,
158
- privilege: AccessLevel,
159
- ): boolean {
160
- const grantedPrivileges = this.getGrantedPrivileges(session, endpoint, clusterId);
161
- if (grantedPrivileges.includes(privilege)) {
162
- return true;
163
- }
164
-
165
- logger.notice(
166
- `Failed access control check for ${endpoint.id}/0x${toHex(clusterId)} and fabricIndex ${session.associatedFabric.fabricIndex}, acl=`,
167
- this.#getAccessControlEntriesForFabric(session.associatedFabric),
168
- "with ISD=",
169
- this.#getIsdFromMessage(session),
170
- "granted privileges=",
171
- grantedPrivileges,
172
- "not contains",
173
- privilege,
174
- );
175
-
176
- return false;
177
- }
178
-
179
- /**
180
- * Determines the granted privileges for the given session, endpoint, and cluster ID and returns them.
181
- */
182
- getGrantedPrivileges(session: SecureSession, endpoint: AclEndpointContext, clusterId: ClusterId): AccessLevel[] {
159
+ ): AccessLevel[] {
183
160
  const endpointId = endpoint.id;
184
- const fabric = session.fabric;
185
- const subjectDesc = this.#getIsdFromMessage(session);
161
+ const fabric = context.fabric;
162
+ const subjectDesc = this.#getIsdFromMessage(context);
186
163
  const acl = fabric ? this.#getAccessControlEntriesForFabric(fabric) : [ImplicitDefaultPaseAclEntry];
187
164
 
188
165
  // Granted privileges set is initially empty
@@ -203,17 +180,11 @@ export class AccessControlManager {
203
180
  // other than the implicit PASE entry, which we will not see explicitly in the
204
181
  // access control list
205
182
  if (aclEntry.fabricIndex === FabricIndex.NO_FABRIC || aclEntry.fabricIndex !== subjectDesc.fabricIndex) {
206
- logger.debug(
207
- "Skipping ACL entry with mismatched fabric index",
208
- aclEntry.fabricIndex,
209
- subjectDesc.fabricIndex,
210
- );
211
183
  continue;
212
184
  }
213
185
 
214
186
  // Auth mode must match
215
187
  if (aclEntry.authMode !== subjectDesc.authMode) {
216
- logger.debug("Skipping ACL entry with mismatched auth mode", aclEntry.authMode, subjectDesc.authMode);
217
188
  continue;
218
189
  }
219
190
 
@@ -304,50 +275,47 @@ export class AccessControlManager {
304
275
  /**
305
276
  * Determines the Incoming Subject Descriptor (ISD) from the given session.
306
277
  */
307
- #getIsdFromMessage(session: SecureSession) {
308
- const fabric = session.fabric;
278
+ #getIsdFromMessage(session: AccessControlContext.Session) {
279
+ const fabricIndex = session.fabric;
309
280
  const isd: IncomingSubjectDescriptor = {
310
281
  isCommissioning: false,
311
282
  authMode: AuthModeNone.None,
312
- subjects: new Array<NodeId>(),
283
+ subjects: new Array<SubjectId>(),
313
284
  fabricIndex: FabricIndex.NO_FABRIC,
314
285
  };
315
286
 
316
- if (session.isPase) {
287
+ const { subject } = session;
288
+ if (subject === undefined) {
289
+ throw new MatterFlowError("ACL error: ACL checks require an authorized subject");
290
+ }
291
+ if (subject.id === NodeId.UNSPECIFIED_NODE_ID) {
292
+ // Pase Session
317
293
  isd.authMode = AccessControl.AccessControlEntryAuthMode.Pase;
318
294
  isd.isCommissioning = true; // Or how "commissioning channel" is defined?
319
- isd.subjects.push(NodeId(0)); // Default Commissioning Passcode ID
320
- if (fabric) {
321
- isd.fabricIndex = fabric.fabricIndex;
295
+ isd.subjects.push(NodeId.UNSPECIFIED_NODE_ID); // Default Commissioning Passcode ID
296
+ if (fabricIndex !== undefined && fabricIndex !== FabricIndex.NO_FABRIC) {
297
+ isd.fabricIndex = fabricIndex;
322
298
  }
323
- } else {
324
- // TODO Add Group session handling when implementing groups
325
- // if (session instanceof SecureGroupSession) {
326
- // Groups
327
- // # Message is assumed to have been decrypted and matched properly prior to
328
- // # this procedure occurring.
329
- // group_id = message.get_dst_group_id()
330
- // group_key_id = sessions_metadata.get_group_key_id(message)
331
- // # Group membership must be verified against Group Key Management Cluster
332
- // if group_key_management_cluster.group_key_map_has_mapping(group_id, group_key_id):
333
- // isd.AuthMode = AuthModeEnum.Group
334
- // isd.Subjects.append(group_id)
335
- // isd.FabricIndex = sessions_metadata.get_fabric_index(message)
336
- // assert(isd.FabricIndex != 0) # cannot be zero
337
- //
338
- // isd.authMode = AccessControl.AccessControlEntryAuthMode.Group;
339
- // } else {
340
-
299
+ } else if (Subject.isGroup(subject)) {
300
+ if (fabricIndex === undefined || fabricIndex === FabricIndex.NO_FABRIC) {
301
+ throw new MatterFlowError("ACL error: fabric needs to be associated for group sessions");
302
+ }
303
+ if (subject.hasValidMapping) {
304
+ isd.authMode = AccessControl.AccessControlEntryAuthMode.Group;
305
+ isd.subjects.push(subject.id);
306
+ isd.fabricIndex = fabricIndex;
307
+ }
308
+ } else if (Subject.isNode(subject)) {
341
309
  // CASE session
310
+ if (fabricIndex === undefined || fabricIndex === FabricIndex.NO_FABRIC) {
311
+ throw new MatterFlowError("ACL error: Case session must be associated with a fabric");
312
+ }
342
313
  isd.authMode = AccessControl.AccessControlEntryAuthMode.Case;
343
- isd.subjects.push(session.peerNodeId);
344
- // Append CASE session CATs which also serve as subjects
345
- session.caseAuthenticatedTags.forEach(cat => isd.subjects.push(NodeId.fromCaseAuthenticatedTag(cat)));
346
- // }
347
- if (fabric === undefined) {
348
- throw new MatterFlowError("ACL error: fabric is undefined");
314
+ isd.subjects.push(subject.id);
315
+ if (subject.catSubjects !== undefined) {
316
+ isd.subjects.push(...subject.catSubjects);
349
317
  }
350
- isd.fabricIndex = fabric.fabricIndex;
318
+ isd.fabricIndex = fabricIndex;
351
319
  }
352
320
 
353
321
  return isd;