@matter/protocol 0.12.4-alpha.0-20250217-b0bba5179 → 0.12.4-alpha.0-20250224-e0964a795

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 (219) hide show
  1. package/dist/cjs/action/client/ClientInteraction.d.ts +38 -0
  2. package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -0
  3. package/dist/cjs/action/client/ClientInteraction.js +91 -0
  4. package/dist/cjs/action/client/ClientInteraction.js.map +6 -0
  5. package/dist/cjs/action/client/index.d.ts +7 -0
  6. package/dist/cjs/action/client/index.d.ts.map +1 -0
  7. package/dist/cjs/action/client/index.js +24 -0
  8. package/dist/cjs/action/client/index.js.map +6 -0
  9. package/dist/cjs/action/index.d.ts +1 -0
  10. package/dist/cjs/action/index.d.ts.map +1 -1
  11. package/dist/cjs/action/index.js +1 -0
  12. package/dist/cjs/action/index.js.map +1 -1
  13. package/dist/cjs/interaction/DecodedDataReport.d.ts +15 -0
  14. package/dist/cjs/interaction/DecodedDataReport.d.ts.map +1 -0
  15. package/dist/cjs/interaction/DecodedDataReport.js +42 -0
  16. package/dist/cjs/interaction/DecodedDataReport.js.map +6 -0
  17. package/dist/cjs/interaction/InteractionClient.d.ts +13 -23
  18. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  19. package/dist/cjs/interaction/InteractionClient.js +99 -127
  20. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  21. package/dist/cjs/interaction/InteractionMessenger.d.ts +94 -1
  22. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  23. package/dist/cjs/interaction/InteractionMessenger.js +56 -37
  24. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  25. package/dist/cjs/interaction/InteractionServer.d.ts +4 -2
  26. package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
  27. package/dist/cjs/interaction/InteractionServer.js +12 -4
  28. package/dist/cjs/interaction/InteractionServer.js.map +1 -1
  29. package/dist/cjs/interaction/SubscriptionClient.d.ts +38 -0
  30. package/dist/cjs/interaction/SubscriptionClient.d.ts.map +1 -0
  31. package/dist/cjs/interaction/SubscriptionClient.js +98 -0
  32. package/dist/cjs/interaction/SubscriptionClient.js.map +6 -0
  33. package/dist/cjs/interaction/index.d.ts +1 -0
  34. package/dist/cjs/interaction/index.d.ts.map +1 -1
  35. package/dist/cjs/interaction/index.js +1 -0
  36. package/dist/cjs/interaction/index.js.map +1 -1
  37. package/dist/cjs/peer/ControllerCommissioner.d.ts +2 -2
  38. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  39. package/dist/cjs/peer/ControllerCommissioner.js +4 -3
  40. package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
  41. package/dist/cjs/peer/InteractionQueue.d.ts +11 -0
  42. package/dist/cjs/peer/InteractionQueue.d.ts.map +1 -0
  43. package/dist/cjs/peer/InteractionQueue.js +42 -0
  44. package/dist/cjs/peer/InteractionQueue.js.map +6 -0
  45. package/dist/cjs/peer/PeerAddressStore.d.ts +1 -1
  46. package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
  47. package/dist/cjs/peer/PeerSet.d.ts +16 -7
  48. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  49. package/dist/cjs/peer/PeerSet.js +58 -61
  50. package/dist/cjs/peer/PeerSet.js.map +1 -1
  51. package/dist/cjs/peer/PhysicalDeviceProperties.d.ts +26 -0
  52. package/dist/cjs/peer/PhysicalDeviceProperties.d.ts.map +1 -0
  53. package/dist/cjs/peer/PhysicalDeviceProperties.js +74 -0
  54. package/dist/cjs/peer/PhysicalDeviceProperties.js.map +6 -0
  55. package/dist/cjs/peer/index.d.ts +1 -0
  56. package/dist/cjs/peer/index.d.ts.map +1 -1
  57. package/dist/cjs/peer/index.js +1 -0
  58. package/dist/cjs/peer/index.js.map +1 -1
  59. package/dist/cjs/protocol/ExchangeManager.d.ts +1 -0
  60. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  61. package/dist/cjs/protocol/ExchangeManager.js +18 -11
  62. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  63. package/dist/cjs/protocol/ExchangeProvider.d.ts +13 -1
  64. package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
  65. package/dist/cjs/protocol/ExchangeProvider.js +2 -0
  66. package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
  67. package/dist/cjs/protocol/ProtocolHandler.d.ts +1 -1
  68. package/dist/cjs/protocol/ProtocolHandler.d.ts.map +1 -1
  69. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts +1 -1
  70. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  71. package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -3
  72. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  73. package/dist/cjs/session/InsecureSession.d.ts.map +1 -1
  74. package/dist/cjs/session/InsecureSession.js +1 -0
  75. package/dist/cjs/session/InsecureSession.js.map +1 -1
  76. package/dist/cjs/session/SecureSession.d.ts.map +1 -1
  77. package/dist/cjs/session/SecureSession.js +4 -0
  78. package/dist/cjs/session/SecureSession.js.map +1 -1
  79. package/dist/cjs/session/Session.d.ts +3 -1
  80. package/dist/cjs/session/Session.d.ts.map +1 -1
  81. package/dist/cjs/session/Session.js +5 -1
  82. package/dist/cjs/session/Session.js.map +1 -1
  83. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  84. package/dist/cjs/session/SessionManager.js +1 -0
  85. package/dist/cjs/session/SessionManager.js.map +1 -1
  86. package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
  87. package/dist/cjs/session/case/CaseClient.js +22 -15
  88. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  89. package/dist/cjs/session/case/CaseServer.d.ts +1 -1
  90. package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
  91. package/dist/cjs/session/case/CaseServer.js +2 -4
  92. package/dist/cjs/session/case/CaseServer.js.map +1 -1
  93. package/dist/cjs/session/pase/PaseServer.d.ts +2 -3
  94. package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
  95. package/dist/cjs/session/pase/PaseServer.js +12 -14
  96. package/dist/cjs/session/pase/PaseServer.js.map +1 -1
  97. package/dist/esm/action/client/ClientInteraction.d.ts +38 -0
  98. package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -0
  99. package/dist/esm/action/client/ClientInteraction.js +71 -0
  100. package/dist/esm/action/client/ClientInteraction.js.map +6 -0
  101. package/dist/esm/action/client/index.d.ts +7 -0
  102. package/dist/esm/action/client/index.d.ts.map +1 -0
  103. package/dist/esm/action/client/index.js +7 -0
  104. package/dist/esm/action/client/index.js.map +6 -0
  105. package/dist/esm/action/index.d.ts +1 -0
  106. package/dist/esm/action/index.d.ts.map +1 -1
  107. package/dist/esm/action/index.js +1 -0
  108. package/dist/esm/action/index.js.map +1 -1
  109. package/dist/esm/interaction/DecodedDataReport.d.ts +15 -0
  110. package/dist/esm/interaction/DecodedDataReport.d.ts.map +1 -0
  111. package/dist/esm/interaction/DecodedDataReport.js +22 -0
  112. package/dist/esm/interaction/DecodedDataReport.js.map +6 -0
  113. package/dist/esm/interaction/InteractionClient.d.ts +13 -23
  114. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  115. package/dist/esm/interaction/InteractionClient.js +101 -134
  116. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  117. package/dist/esm/interaction/InteractionMessenger.d.ts +94 -1
  118. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  119. package/dist/esm/interaction/InteractionMessenger.js +56 -37
  120. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  121. package/dist/esm/interaction/InteractionServer.d.ts +4 -2
  122. package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
  123. package/dist/esm/interaction/InteractionServer.js +12 -4
  124. package/dist/esm/interaction/InteractionServer.js.map +1 -1
  125. package/dist/esm/interaction/SubscriptionClient.d.ts +38 -0
  126. package/dist/esm/interaction/SubscriptionClient.d.ts.map +1 -0
  127. package/dist/esm/interaction/SubscriptionClient.js +78 -0
  128. package/dist/esm/interaction/SubscriptionClient.js.map +6 -0
  129. package/dist/esm/interaction/index.d.ts +1 -0
  130. package/dist/esm/interaction/index.d.ts.map +1 -1
  131. package/dist/esm/interaction/index.js +1 -0
  132. package/dist/esm/interaction/index.js.map +1 -1
  133. package/dist/esm/peer/ControllerCommissioner.d.ts +2 -2
  134. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  135. package/dist/esm/peer/ControllerCommissioner.js +6 -5
  136. package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
  137. package/dist/esm/peer/InteractionQueue.d.ts +11 -0
  138. package/dist/esm/peer/InteractionQueue.d.ts.map +1 -0
  139. package/dist/esm/peer/InteractionQueue.js +22 -0
  140. package/dist/esm/peer/InteractionQueue.js.map +6 -0
  141. package/dist/esm/peer/PeerAddressStore.d.ts +1 -1
  142. package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
  143. package/dist/esm/peer/PeerSet.d.ts +16 -7
  144. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  145. package/dist/esm/peer/PeerSet.js +59 -62
  146. package/dist/esm/peer/PeerSet.js.map +1 -1
  147. package/dist/esm/peer/PhysicalDeviceProperties.d.ts +26 -0
  148. package/dist/esm/peer/PhysicalDeviceProperties.d.ts.map +1 -0
  149. package/dist/esm/peer/PhysicalDeviceProperties.js +54 -0
  150. package/dist/esm/peer/PhysicalDeviceProperties.js.map +6 -0
  151. package/dist/esm/peer/index.d.ts +1 -0
  152. package/dist/esm/peer/index.d.ts.map +1 -1
  153. package/dist/esm/peer/index.js +1 -0
  154. package/dist/esm/peer/index.js.map +1 -1
  155. package/dist/esm/protocol/ExchangeManager.d.ts +1 -0
  156. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  157. package/dist/esm/protocol/ExchangeManager.js +18 -11
  158. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  159. package/dist/esm/protocol/ExchangeProvider.d.ts +13 -1
  160. package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
  161. package/dist/esm/protocol/ExchangeProvider.js +2 -0
  162. package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
  163. package/dist/esm/protocol/ProtocolHandler.d.ts +1 -1
  164. package/dist/esm/protocol/ProtocolHandler.d.ts.map +1 -1
  165. package/dist/esm/securechannel/SecureChannelProtocol.d.ts +1 -1
  166. package/dist/esm/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  167. package/dist/esm/securechannel/SecureChannelProtocol.js +1 -3
  168. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  169. package/dist/esm/session/InsecureSession.d.ts.map +1 -1
  170. package/dist/esm/session/InsecureSession.js +1 -0
  171. package/dist/esm/session/InsecureSession.js.map +1 -1
  172. package/dist/esm/session/SecureSession.d.ts.map +1 -1
  173. package/dist/esm/session/SecureSession.js +4 -0
  174. package/dist/esm/session/SecureSession.js.map +1 -1
  175. package/dist/esm/session/Session.d.ts +3 -1
  176. package/dist/esm/session/Session.d.ts.map +1 -1
  177. package/dist/esm/session/Session.js +6 -2
  178. package/dist/esm/session/Session.js.map +1 -1
  179. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  180. package/dist/esm/session/SessionManager.js +1 -0
  181. package/dist/esm/session/SessionManager.js.map +1 -1
  182. package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
  183. package/dist/esm/session/case/CaseClient.js +22 -15
  184. package/dist/esm/session/case/CaseClient.js.map +1 -1
  185. package/dist/esm/session/case/CaseServer.d.ts +1 -1
  186. package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
  187. package/dist/esm/session/case/CaseServer.js +2 -4
  188. package/dist/esm/session/case/CaseServer.js.map +1 -1
  189. package/dist/esm/session/pase/PaseServer.d.ts +2 -3
  190. package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
  191. package/dist/esm/session/pase/PaseServer.js +12 -14
  192. package/dist/esm/session/pase/PaseServer.js.map +1 -1
  193. package/package.json +6 -6
  194. package/src/action/client/ClientInteraction.ts +110 -0
  195. package/src/action/client/index.ts +7 -0
  196. package/src/action/index.ts +1 -0
  197. package/src/interaction/DecodedDataReport.ts +29 -0
  198. package/src/interaction/InteractionClient.ts +112 -164
  199. package/src/interaction/InteractionMessenger.ts +63 -43
  200. package/src/interaction/InteractionServer.ts +18 -5
  201. package/src/interaction/SubscriptionClient.ts +107 -0
  202. package/src/interaction/index.ts +1 -0
  203. package/src/peer/ControllerCommissioner.ts +7 -6
  204. package/src/peer/InteractionQueue.ts +22 -0
  205. package/src/peer/PeerAddressStore.ts +1 -1
  206. package/src/peer/PeerSet.ts +69 -76
  207. package/src/peer/PhysicalDeviceProperties.ts +80 -0
  208. package/src/peer/index.ts +1 -0
  209. package/src/protocol/ExchangeManager.ts +19 -11
  210. package/src/protocol/ExchangeProvider.ts +14 -1
  211. package/src/protocol/ProtocolHandler.ts +1 -1
  212. package/src/securechannel/SecureChannelProtocol.ts +1 -3
  213. package/src/session/InsecureSession.ts +1 -0
  214. package/src/session/SecureSession.ts +4 -0
  215. package/src/session/Session.ts +7 -2
  216. package/src/session/SessionManager.ts +1 -0
  217. package/src/session/case/CaseClient.ts +18 -12
  218. package/src/session/case/CaseServer.ts +3 -5
  219. package/src/session/pase/PaseServer.ts +13 -15
@@ -48,6 +48,7 @@ export class MessageChannel implements Channel<Message> {
48
48
  closeCallback?: () => Promise<void>,
49
49
  ) {
50
50
  this.#closeCallback = closeCallback;
51
+ this.session.destroyed.on(() => this.close());
51
52
  }
52
53
 
53
54
  set closeCallback(callback: () => Promise<void>) {
@@ -149,6 +150,10 @@ export class ExchangeManager {
149
150
  return instance;
150
151
  }
151
152
 
153
+ get channels() {
154
+ return this.#channelManager;
155
+ }
156
+
152
157
  hasProtocolHandler(protocolId: number) {
153
158
  return this.#protocols.has(protocolId);
154
159
  }
@@ -158,10 +163,10 @@ export class ExchangeManager {
158
163
  }
159
164
 
160
165
  addProtocolHandler(protocol: ProtocolHandler) {
161
- if (this.hasProtocolHandler(protocol.getId())) {
162
- throw new ImplementationError(`Handler for protocol ${protocol.getId()} already registered.`);
166
+ if (this.hasProtocolHandler(protocol.id)) {
167
+ throw new ImplementationError(`Handler for protocol ${protocol.id} already registered.`);
163
168
  }
164
- this.#protocols.set(protocol.getId(), protocol);
169
+ this.#protocols.set(protocol.id, protocol);
165
170
  }
166
171
 
167
172
  initiateExchange(address: PeerAddress, protocolId: number) {
@@ -272,7 +277,7 @@ export class ExchangeManager {
272
277
  !message.payloadHeader.requiresAck
273
278
  ) {
274
279
  logger.debug(
275
- `Ignoring unsolicited standalone ack message ${messageId} for protocol ${message.payloadHeader.protocolId} and exchange id ${message.payloadHeader.exchangeId}.`,
280
+ `Ignoring unsolicited standalone ack message ${messageId} for protocol ${message.payloadHeader.protocolId} and exchange id ${message.payloadHeader.exchangeId} on channel ${channel.name}`,
276
281
  );
277
282
  return;
278
283
  }
@@ -295,7 +300,7 @@ export class ExchangeManager {
295
300
  });
296
301
  await exchange.close();
297
302
  logger.debug(
298
- `Ignoring unsolicited message ${messageId} for protocol ${message.payloadHeader.protocolId}.`,
303
+ `Ignoring unsolicited message ${messageId} for protocol ${message.payloadHeader.protocolId} on channel ${channel.name}`,
299
304
  );
300
305
  } else {
301
306
  if (protocolHandler === undefined) {
@@ -303,14 +308,14 @@ export class ExchangeManager {
303
308
  }
304
309
  if (isDuplicate) {
305
310
  logger.info(
306
- `Ignoring duplicate message ${messageId} (requires no ack) for protocol ${message.payloadHeader.protocolId}.`,
311
+ `Ignoring duplicate message ${messageId} (requires no ack) for protocol ${message.payloadHeader.protocolId} on channel ${channel.name}`,
307
312
  );
308
313
  return;
309
314
  } else {
310
315
  logger.info(
311
316
  `Discarding unexpected message ${messageId} for protocol ${
312
317
  message.payloadHeader.protocolId
313
- }, exchangeIndex ${exchangeIndex} and sessionId ${session.id} : ${Logger.toJSON(message)}`,
318
+ }, exchangeIndex ${exchangeIndex} and sessionId ${session.id} on channel ${channel.name}: ${Logger.toJSON(message)}`,
314
319
  );
315
320
  }
316
321
  }
@@ -355,7 +360,7 @@ export class ExchangeManager {
355
360
  }
356
361
  if (session.sendCloseMessageWhenClosing) {
357
362
  const channel = this.#channelManager.getChannelForSession(session);
358
- logger.debug(`Channel for session ${session.name} is ${channel?.name}`);
363
+ logger.debug(`Channel for session ${sessionName} is ${channel?.name}`);
359
364
  if (channel !== undefined) {
360
365
  const exchange = this.initiateExchangeWithChannel(channel, SECURE_CHANNEL_PROTOCOL_ID);
361
366
  if (exchange !== undefined) {
@@ -422,18 +427,21 @@ export class ExchangeManager {
422
427
  transportInterface.onData((socket, data) => {
423
428
  if (udpInterface && data.length > socket.maxPayloadSize) {
424
429
  logger.warn(
425
- `Ignoring UDP message with size ${data.length} from ${socket.name}, which is larger than the maximum allowed size of ${socket.maxPayloadSize}.`,
430
+ `Ignoring UDP message on channel ${socket.name} with size ${data.length} from ${socket.name}, which is larger than the maximum allowed size of ${socket.maxPayloadSize}.`,
426
431
  );
427
432
  return;
428
433
  }
429
434
 
430
435
  try {
431
436
  this.onMessage(socket, data).catch(error =>
432
- logger.info(error instanceof MatterError ? error.message : error),
437
+ logger.info(
438
+ `Error on channel ${socket.name}:`,
439
+ error instanceof MatterError ? error.message : error,
440
+ ),
433
441
  );
434
442
  } catch (error) {
435
443
  logger.info(
436
- "Ignoring UDP message with error",
444
+ `Ignoring UDP message on channel ${socket.name} with error`,
437
445
  error instanceof MatterError ? error.message : error,
438
446
  );
439
447
  }
@@ -12,8 +12,13 @@ import { MessageExchange } from "../protocol/MessageExchange.js";
12
12
  import { ProtocolHandler } from "../protocol/ProtocolHandler.js";
13
13
  import { Session } from "../session/Session.js";
14
14
 
15
+ /**
16
+ * Interface for obtaining an exchange with a specific peer.
17
+ */
15
18
  export abstract class ExchangeProvider {
16
- protected constructor(protected readonly exchangeManager: ExchangeManager) {}
19
+ abstract readonly supportsReconnect: boolean;
20
+
21
+ constructor(protected readonly exchangeManager: ExchangeManager) {}
17
22
 
18
23
  hasProtocolHandler(protocolId: number) {
19
24
  return this.exchangeManager.hasProtocolHandler(protocolId);
@@ -33,8 +38,12 @@ export abstract class ExchangeProvider {
33
38
  abstract channelType: ChannelType;
34
39
  }
35
40
 
41
+ /**
42
+ * Manages an exchange over an established channel.
43
+ */
36
44
  export class DedicatedChannelExchangeProvider extends ExchangeProvider {
37
45
  #channel: MessageChannel;
46
+ readonly supportsReconnect = false;
38
47
 
39
48
  constructor(exchangeManager: ExchangeManager, channel: MessageChannel) {
40
49
  super(exchangeManager);
@@ -58,7 +67,11 @@ export class DedicatedChannelExchangeProvider extends ExchangeProvider {
58
67
  }
59
68
  }
60
69
 
70
+ /**
71
+ * Manages peer exchange that will reestablish automatically in the case of communication failure.
72
+ */
61
73
  export class ReconnectableExchangeProvider extends ExchangeProvider {
74
+ readonly supportsReconnect = true;
62
75
  readonly #address: PeerAddress;
63
76
  readonly #reconnectChannelFunc: () => Promise<void>;
64
77
  readonly #channelUpdated = Observable<[void]>();
@@ -8,7 +8,7 @@ import { Message } from "../codec/MessageCodec.js";
8
8
  import { MessageExchange } from "./MessageExchange.js";
9
9
 
10
10
  export interface ProtocolHandler {
11
- getId(): number;
11
+ readonly id: number;
12
12
  onNewExchange(exchange: MessageExchange, message: Message): Promise<void>;
13
13
  close(): Promise<void>;
14
14
  }
@@ -28,9 +28,7 @@ import { TlvSecureChannelStatusMessage } from "./SecureChannelStatusMessageSchem
28
28
  const logger = Logger.get("SecureChannelProtocol");
29
29
 
30
30
  export class StatusReportOnlySecureChannelProtocol implements ProtocolHandler {
31
- getId(): number {
32
- return SECURE_CHANNEL_PROTOCOL_ID;
33
- }
31
+ readonly id = SECURE_CHANNEL_PROTOCOL_ID;
34
32
 
35
33
  async onNewExchange(exchange: MessageExchange, message: Message) {
36
34
  const messageType = message.payloadHeader.messageType;
@@ -87,6 +87,7 @@ export class InsecureSession extends Session {
87
87
 
88
88
  async destroy() {
89
89
  await this.end();
90
+ await this.destroyed.emit();
90
91
  }
91
92
 
92
93
  async end() {
@@ -327,9 +327,13 @@ export class SecureSession extends Session {
327
327
  await this.closer;
328
328
  } catch (error) {
329
329
  NoChannelError.accept(error);
330
+ } finally {
331
+ await this.destroyed.emit();
330
332
  }
333
+ return;
331
334
  }
332
335
  }
336
+ await this.destroyed.emit();
333
337
  }
334
338
 
335
339
  /**
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { Time } from "#general";
7
+ import { AsyncObservable, Time } from "#general";
8
8
  import { NodeId } from "#types";
9
9
  import { DecodedMessage, DecodedPacket, Message, Packet } from "../codec/MessageCodec.js";
10
10
  import { Fabric } from "../fabric/Fabric.js";
@@ -76,9 +76,10 @@ export abstract class Session {
76
76
  /**
77
77
  * If the ExchangeManager performs async work to clean up a session it sets this promise. This is because
78
78
  * historically we didn't return from destroy() until ExchangeManager was complete. Not sure if this is entirely
79
- * necessary but it makes sense so this allows us to maintain the old behavior.
79
+ * necessary, but it makes sense so this allows us to maintain the old behavior.
80
80
  */
81
81
  closer?: Promise<void>;
82
+ #destroyed = AsyncObservable<[]>();
82
83
 
83
84
  constructor(args: {
84
85
  manager?: SessionManager;
@@ -117,6 +118,10 @@ export abstract class Session {
117
118
  }
118
119
  }
119
120
 
121
+ get destroyed() {
122
+ return this.#destroyed;
123
+ }
124
+
120
125
  notifyActivity(messageReceived: boolean) {
121
126
  this.timestamp = Time.nowMs();
122
127
  if (messageReceived) {
@@ -386,6 +386,7 @@ export class SessionManager {
386
386
  const secureSession = session;
387
387
  if (secureSession.peerIs(address)) {
388
388
  await secureSession.destroy(sendClose, false);
389
+ this.#sessions.delete(session);
389
390
  }
390
391
  }
391
392
  }
@@ -79,7 +79,12 @@ export class CaseClient {
79
79
  if (sigma2Resume !== undefined) {
80
80
  // Process sigma2 resume
81
81
  if (resumptionRecord === undefined) throw new UnexpectedDataError("Received an unexpected sigma2Resume.");
82
- const { sharedSecret, fabric, sessionParameters: resumptionSessionParams } = resumptionRecord;
82
+ const {
83
+ sharedSecret,
84
+ fabric,
85
+ sessionParameters: resumptionSessionParams,
86
+ caseAuthenticatedTags,
87
+ } = resumptionRecord;
83
88
  const { responderSessionId: peerSessionId, resumptionId, resumeMic } = sigma2Resume;
84
89
 
85
90
  // We use the Fallbacks for the session parameters overridden by our stored ones from the resumption record
@@ -103,10 +108,11 @@ export class CaseClient {
103
108
  isInitiator: true,
104
109
  isResumption: true,
105
110
  peerSessionParameters: sessionParameters,
111
+ caseAuthenticatedTags,
106
112
  });
107
113
  await messenger.sendSuccess();
108
114
  logger.info(
109
- `Case client: Session resumed with ${messenger.getChannelName()} and parameters`,
115
+ `Case client: Session ${secureSession.id} successfully resumed with ${messenger.getChannelName()} for Fabric ${NodeId.toHexString(fabric.nodeId)}(index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)} and parameters`,
110
116
  secureSession.parameterDiagnostics(),
111
117
  );
112
118
 
@@ -157,17 +163,12 @@ export class CaseClient {
157
163
 
158
164
  if (peerNodeIdNOCert !== peerNodeId) {
159
165
  throw new UnexpectedDataError(
160
- "The node ID in the peer certificate doesn't match the expected peer node ID",
161
- );
162
- }
163
- if (peerNodeIdNOCert !== peerNodeId) {
164
- throw new UnexpectedDataError(
165
- "The node ID in the peer certificate doesn't match the expected peer node ID",
166
+ `The node ID in the peer certificate ${peerNodeIdNOCert} doesn't match the expected peer node ID ${peerNodeId}`,
166
167
  );
167
168
  }
168
169
  if (peerFabricIdNOCert !== fabric.fabricId) {
169
170
  throw new UnexpectedDataError(
170
- "The fabric ID in the peer certificate doesn't match the expected fabric ID",
171
+ `The fabric ID in the peer certificate ${peerFabricIdNOCert} doesn't match the expected fabric ID ${fabric.fabricId}`,
171
172
  );
172
173
  }
173
174
  if (peerIntermediateCACert !== undefined) {
@@ -175,9 +176,9 @@ export class CaseClient {
175
176
  subject: { fabricId: peerFabricIdIcaCert },
176
177
  } = TlvIntermediateCertificate.decode(peerIntermediateCACert);
177
178
 
178
- if (peerFabricIdIcaCert !== fabric.fabricId) {
179
+ if (peerFabricIdIcaCert !== undefined && peerFabricIdIcaCert !== fabric.fabricId) {
179
180
  throw new UnexpectedDataError(
180
- "The fabric ID in the peer intermediate CA certificate doesn't match the expected fabric ID",
181
+ `The fabric ID in the peer intermediate CA certificate ${peerFabricIdIcaCert} doesn't match the expected fabric ID ${fabric.fabricId}`,
181
182
  );
182
183
  }
183
184
  }
@@ -199,6 +200,7 @@ export class CaseClient {
199
200
  await messenger.waitForSuccess("Sigma3-Success");
200
201
 
201
202
  // All good! Create secure session
203
+ const { caseAuthenticatedTags } = resumptionRecord ?? {}; // Even if resumption does not work try to reuse the caseAuthenticatedTags
202
204
  const secureSessionSalt = Bytes.concat(
203
205
  operationalIdentityProtectionKey,
204
206
  Crypto.hash([sigma1Bytes, sigma2Bytes, sigma3Bytes]),
@@ -213,9 +215,12 @@ export class CaseClient {
213
215
  isInitiator: true,
214
216
  isResumption: false,
215
217
  peerSessionParameters: sessionParameters,
218
+ caseAuthenticatedTags,
216
219
  });
217
220
  logger.info(
218
- `Case client: Paired successfully with ${messenger.getChannelName()} and parameters`,
221
+ `Case client Session ${secureSession.id} established successfully with ${messenger.getChannelName()} for Fabric ${NodeId.toHexString(
222
+ fabric.nodeId,
223
+ )}(index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)}and parameters`,
219
224
  secureSession.parameterDiagnostics(),
220
225
  );
221
226
  resumptionRecord = {
@@ -224,6 +229,7 @@ export class CaseClient {
224
229
  sharedSecret,
225
230
  resumptionId: peerResumptionId,
226
231
  sessionParameters: secureSession.parameters,
232
+ caseAuthenticatedTags,
227
233
  };
228
234
  }
229
235
 
@@ -30,6 +30,8 @@ import { CaseServerMessenger } from "./CaseMessenger.js";
30
30
  const logger = Logger.get("CaseServer");
31
31
 
32
32
  export class CaseServer implements ProtocolHandler {
33
+ readonly id = SECURE_CHANNEL_PROTOCOL_ID;
34
+
33
35
  #sessions: SessionManager;
34
36
  #fabrics: FabricManager;
35
37
 
@@ -58,10 +60,6 @@ export class CaseServer implements ProtocolHandler {
58
60
  }
59
61
  }
60
62
 
61
- getId(): number {
62
- return SECURE_CHANNEL_PROTOCOL_ID;
63
- }
64
-
65
63
  private async handleSigma1(messenger: CaseServerMessenger) {
66
64
  logger.info(`Received pairing request from ${messenger.getChannelName()}`);
67
65
  // Generate pairing info
@@ -234,7 +232,7 @@ export class CaseServer implements ProtocolHandler {
234
232
  caseAuthenticatedTags,
235
233
  });
236
234
  logger.info(
237
- `session ${secureSession.id} created with ${messenger.getChannelName()} for Fabric ${NodeId.toHexString(
235
+ `Session ${secureSession.id} created with ${messenger.getChannelName()} for Fabric ${NodeId.toHexString(
238
236
  fabric.nodeId,
239
237
  )}(index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)}`,
240
238
  "with CATs",
@@ -33,8 +33,10 @@ const PASE_COMMISSIONING_MAX_ERRORS = 20;
33
33
  export class MaximumPasePairingErrorsReachedError extends MatterFlowError {}
34
34
 
35
35
  export class PaseServer implements ProtocolHandler {
36
- private pairingTimer: Timer | undefined;
37
- private pairingErrors = 0;
36
+ readonly id = SECURE_CHANNEL_PROTOCOL_ID;
37
+
38
+ #pairingTimer: Timer | undefined;
39
+ #pairingErrors = 0;
38
40
 
39
41
  static async fromPin(sessions: SessionManager, setupPinCode: number, pbkdfParameters: PbkdfParameters) {
40
42
  const { w0, L } = await Spake2p.computeW0L(pbkdfParameters, setupPinCode);
@@ -58,18 +60,14 @@ export class PaseServer implements ProtocolHandler {
58
60
  private readonly pbkdfParameters?: PbkdfParameters,
59
61
  ) {}
60
62
 
61
- getId(): number {
62
- return SECURE_CHANNEL_PROTOCOL_ID;
63
- }
64
-
65
63
  async onNewExchange(exchange: MessageExchange) {
66
64
  const messenger = new PaseServerMessenger(exchange);
67
65
  try {
68
66
  await this.handlePairingRequest(messenger);
69
67
  } catch (error) {
70
- this.pairingErrors++;
68
+ this.#pairingErrors++;
71
69
  logger.error(
72
- `An error occurred during the PASE commissioning (${this.pairingErrors}/${PASE_COMMISSIONING_MAX_ERRORS}):`,
70
+ `An error occurred during the PASE commissioning (${this.#pairingErrors}/${PASE_COMMISSIONING_MAX_ERRORS}):`,
73
71
  error,
74
72
  );
75
73
 
@@ -77,7 +75,7 @@ export class PaseServer implements ProtocolHandler {
77
75
  const sendError = !(error instanceof ChannelStatusResponseError);
78
76
  await this.cancelPairing(messenger, sendError);
79
77
 
80
- if (this.pairingErrors >= PASE_COMMISSIONING_MAX_ERRORS) {
78
+ if (this.#pairingErrors >= PASE_COMMISSIONING_MAX_ERRORS) {
81
79
  throw new MaximumPasePairingErrorsReachedError(
82
80
  `Pase server: Too many errors during PASE commissioning, aborting commissioning window`,
83
81
  );
@@ -99,7 +97,7 @@ export class PaseServer implements ProtocolHandler {
99
97
  );
100
98
  }
101
99
 
102
- if (this.pairingTimer !== undefined && this.pairingTimer.isRunning) {
100
+ if (this.#pairingTimer !== undefined && this.#pairingTimer.isRunning) {
103
101
  throw new MatterFlowError(
104
102
  "Pase server: Pairing already in progress (PASE establishment Timer running), ignoring new exchange.",
105
103
  );
@@ -107,7 +105,7 @@ export class PaseServer implements ProtocolHandler {
107
105
 
108
106
  logger.info(`Received pairing request from ${messenger.getChannelName()}.`);
109
107
 
110
- this.pairingTimer = Time.getTimer("PASE pairing timeout", PASE_PAIRING_TIMEOUT_MS, () =>
108
+ this.#pairingTimer = Time.getTimer("PASE pairing timeout", PASE_PAIRING_TIMEOUT_MS, () =>
111
109
  this.cancelPairing(messenger),
112
110
  ).start();
113
111
 
@@ -167,13 +165,13 @@ export class PaseServer implements ProtocolHandler {
167
165
  await messenger.sendSuccess();
168
166
  await messenger.close();
169
167
 
170
- this.pairingTimer?.stop();
171
- this.pairingTimer = undefined;
168
+ this.#pairingTimer?.stop();
169
+ this.#pairingTimer = undefined;
172
170
  }
173
171
 
174
172
  async cancelPairing(messenger: PaseServerMessenger, sendError = true) {
175
- this.pairingTimer?.stop();
176
- this.pairingTimer = undefined;
173
+ this.#pairingTimer?.stop();
174
+ this.#pairingTimer = undefined;
177
175
 
178
176
  if (sendError) {
179
177
  await messenger.sendError(ProtocolStatusCode.InvalidParam);