@project-chip/matter.js 0.9.1 → 0.9.2

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 (38) hide show
  1. package/dist/cjs/model/models/AttributeModel.d.ts +1 -0
  2. package/dist/cjs/model/models/AttributeModel.d.ts.map +1 -1
  3. package/dist/cjs/model/models/AttributeModel.js +3 -1
  4. package/dist/cjs/model/models/AttributeModel.js.map +2 -2
  5. package/dist/cjs/node/server/TransactionalInteractionServer.d.ts.map +1 -1
  6. package/dist/cjs/node/server/TransactionalInteractionServer.js +15 -2
  7. package/dist/cjs/node/server/TransactionalInteractionServer.js.map +2 -2
  8. package/dist/cjs/protocol/ChannelManager.js +1 -1
  9. package/dist/cjs/protocol/ChannelManager.js.map +2 -2
  10. package/dist/cjs/protocol/interaction/InteractionServer.d.ts +6 -0
  11. package/dist/cjs/protocol/interaction/InteractionServer.d.ts.map +1 -1
  12. package/dist/cjs/protocol/interaction/InteractionServer.js +75 -20
  13. package/dist/cjs/protocol/interaction/InteractionServer.js.map +2 -2
  14. package/dist/cjs/protocol/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  15. package/dist/cjs/protocol/securechannel/SecureChannelProtocol.js +4 -2
  16. package/dist/cjs/protocol/securechannel/SecureChannelProtocol.js.map +2 -2
  17. package/dist/esm/model/models/AttributeModel.d.ts +1 -0
  18. package/dist/esm/model/models/AttributeModel.d.ts.map +1 -1
  19. package/dist/esm/model/models/AttributeModel.js +3 -1
  20. package/dist/esm/model/models/AttributeModel.js.map +2 -2
  21. package/dist/esm/node/server/TransactionalInteractionServer.d.ts.map +1 -1
  22. package/dist/esm/node/server/TransactionalInteractionServer.js +15 -2
  23. package/dist/esm/node/server/TransactionalInteractionServer.js.map +2 -2
  24. package/dist/esm/protocol/ChannelManager.js +1 -1
  25. package/dist/esm/protocol/ChannelManager.js.map +2 -2
  26. package/dist/esm/protocol/interaction/InteractionServer.d.ts +6 -0
  27. package/dist/esm/protocol/interaction/InteractionServer.d.ts.map +1 -1
  28. package/dist/esm/protocol/interaction/InteractionServer.js +75 -20
  29. package/dist/esm/protocol/interaction/InteractionServer.js.map +2 -2
  30. package/dist/esm/protocol/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  31. package/dist/esm/protocol/securechannel/SecureChannelProtocol.js +4 -2
  32. package/dist/esm/protocol/securechannel/SecureChannelProtocol.js.map +2 -2
  33. package/package.json +3 -3
  34. package/src/model/models/AttributeModel.ts +2 -0
  35. package/src/node/server/TransactionalInteractionServer.ts +21 -6
  36. package/src/protocol/ChannelManager.ts +1 -1
  37. package/src/protocol/interaction/InteractionServer.ts +87 -22
  38. package/src/protocol/securechannel/SecureChannelProtocol.ts +3 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/protocol/interaction/InteractionServer.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { MatterDevice } from \"../../MatterDevice.js\";\nimport { TlvNoResponse } from \"../../cluster/Cluster.js\";\nimport {\n AnyAttributeServer,\n AttributeServer,\n FabricScopedAttributeServer,\n} from \"../../cluster/server/AttributeServer.js\";\nimport { CommandServer } from \"../../cluster/server/CommandServer.js\";\nimport { EventServer } from \"../../cluster/server/EventServer.js\";\nimport { Message, SessionType } from \"../../codec/MessageCodec.js\";\nimport { InternalError, MatterFlowError } from \"../../common/MatterError.js\";\nimport { tryCatch, tryCatchAsync } from \"../../common/TryCatchHandler.js\";\nimport { ValidationError } from \"../../common/ValidationError.js\";\nimport { Crypto } from \"../../crypto/Crypto.js\";\nimport { AttributeId } from \"../../datatype/AttributeId.js\";\nimport { ClusterId } from \"../../datatype/ClusterId.js\";\nimport { CommandId } from \"../../datatype/CommandId.js\";\nimport { EndpointNumber } from \"../../datatype/EndpointNumber.js\";\nimport { EventId } from \"../../datatype/EventId.js\";\nimport { EventNumber } from \"../../datatype/EventNumber.js\";\nimport { NodeId } from \"../../datatype/NodeId.js\";\nimport { EndpointInterface } from \"../../endpoint/EndpointInterface.js\";\nimport { Diagnostic } from \"../../log/Diagnostic.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { MessageExchange } from \"../../protocol/MessageExchange.js\";\nimport { ProtocolHandler } from \"../../protocol/ProtocolHandler.js\";\nimport { EventHandler } from \"../../protocol/interaction/EventHandler.js\";\nimport { NoAssociatedFabricError, SecureSession, assertSecureSession } from \"../../session/SecureSession.js\";\nimport { ArraySchema } from \"../../tlv/TlvArray.js\";\nimport { TlvNoArguments } from \"../../tlv/TlvNoArguments.js\";\nimport { TypeFromSchema } from \"../../tlv/TlvSchema.js\";\nimport {\n decodeAttributeValueWithSchema,\n decodeListAttributeValueWithSchema,\n expandPathsInAttributeData,\n} from \"./AttributeDataDecoder.js\";\nimport {\n AttributeReportPayload,\n DataReportPayload,\n EventDataPayload,\n EventReportPayload,\n} from \"./AttributeDataEncoder.js\";\nimport { InteractionEndpointStructure } from \"./InteractionEndpointStructure.js\";\nimport {\n InteractionRecipient,\n InteractionServerMessenger,\n InvokeRequest,\n InvokeResponse,\n MessageType,\n ReadRequest,\n SubscribeRequest,\n TimedRequest,\n WriteRequest,\n WriteResponse,\n} from \"./InteractionMessenger.js\";\nimport {\n TlvAttributePath,\n TlvClusterPath,\n TlvCommandPath,\n TlvEventFilter,\n TlvEventPath,\n TlvInvokeResponseData,\n TlvSubscribeResponse,\n} from \"./InteractionProtocol.js\";\nimport { StatusCode, StatusResponseError } from \"./StatusCode.js\";\nimport { SubscriptionHandler } from \"./SubscriptionHandler.js\";\nimport { SubscriptionOptions } from \"./SubscriptionOptions.js\";\n\nexport const INTERACTION_PROTOCOL_ID = 0x0001;\nexport const INTERACTION_MODEL_REVISION = 11;\n\nconst logger = Logger.get(\"InteractionServer\");\n\nexport interface CommandPath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n commandId: CommandId;\n}\n\nexport interface AttributePath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n attributeId: AttributeId;\n}\n\nexport interface EventPath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n eventId: EventId;\n}\n\nexport interface AttributeWithPath {\n path: AttributePath;\n attribute: AnyAttributeServer<any>;\n}\n\nexport interface EventWithPath {\n path: EventPath;\n event: EventServer<any, any>;\n}\n\nexport interface CommandWithPath {\n path: CommandPath;\n command: CommandServer<any, any>;\n}\n\nexport function genericElementPathToId(\n endpointId: EndpointNumber | undefined,\n clusterId: ClusterId | undefined,\n elementId: number | undefined,\n) {\n return `${endpointId}/${clusterId}/${elementId}`;\n}\n\nexport function commandPathToId({ endpointId, clusterId, commandId }: CommandPath) {\n return genericElementPathToId(endpointId, clusterId, commandId);\n}\n\nexport function attributePathToId({ endpointId, clusterId, attributeId }: TypeFromSchema<typeof TlvAttributePath>) {\n return genericElementPathToId(endpointId, clusterId, attributeId);\n}\n\nexport function eventPathToId({ endpointId, clusterId, eventId }: TypeFromSchema<typeof TlvEventPath>) {\n return genericElementPathToId(endpointId, clusterId, eventId);\n}\n\nexport function clusterPathToId({ nodeId, endpointId, clusterId }: TypeFromSchema<typeof TlvClusterPath>) {\n return `${nodeId}/${endpointId}/${clusterId}`;\n}\n\nfunction isConcreteAttributePath(\n path: TypeFromSchema<typeof TlvAttributePath>,\n): path is TypeFromSchema<typeof TlvAttributePath> & AttributePath {\n const { endpointId, clusterId, attributeId } = path;\n return endpointId !== undefined && clusterId !== undefined && attributeId !== undefined;\n}\n\nfunction isConcreteEventPath(\n path: TypeFromSchema<typeof TlvEventPath>,\n): path is TypeFromSchema<typeof TlvEventPath> & EventPath {\n const { endpointId, clusterId, eventId } = path;\n return endpointId !== undefined && clusterId !== undefined && eventId !== undefined;\n}\n\nfunction isConcreteCommandPath(\n path: TypeFromSchema<typeof TlvCommandPath>,\n): path is TypeFromSchema<typeof TlvCommandPath> & CommandPath {\n const { endpointId, clusterId, commandId } = path;\n return endpointId !== undefined && clusterId !== undefined && commandId !== undefined;\n}\n\n/**\n * Translates interactions from the Matter protocol to Matter.js APIs.\n */\nexport class InteractionServer implements ProtocolHandler<MatterDevice>, InteractionRecipient {\n #endpointStructure;\n #nextSubscriptionId = Crypto.getRandomUInt32();\n readonly #subscriptionMap = new Map<number, SubscriptionHandler>();\n #isClosing = false;\n #subscriptionConfig: SubscriptionOptions.Configuration;\n #eventHandler: EventHandler;\n\n constructor({ subscriptionOptions, eventHandler, endpointStructure }: InteractionServer.Configuration) {\n this.#subscriptionConfig = SubscriptionOptions.configurationFor(subscriptionOptions);\n this.#eventHandler = eventHandler;\n this.#endpointStructure = endpointStructure;\n\n this.#endpointStructure.change.on(() => {\n for (const subscription of this.#subscriptionMap.values()) {\n subscription.updateSubscription();\n }\n });\n }\n\n getId() {\n return INTERACTION_PROTOCOL_ID;\n }\n\n protected get isClosing() {\n return this.#isClosing;\n }\n\n async onNewExchange(exchange: MessageExchange<MatterDevice>) {\n // Note - changes here must be copied to TransactionalInteractionServer as it does not call super() to avoid\n // the stack frame\n if (this.#isClosing) return; // We are closing, ignore anything newly incoming\n await new InteractionServerMessenger(exchange).handleRequest(this);\n }\n\n async handleReadRequest(\n exchange: MessageExchange<MatterDevice>,\n {\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n isFabricFiltered,\n interactionModelRevision,\n }: ReadRequest,\n message: Message,\n ): Promise<DataReportPayload> {\n logger.debug(\n `Received read request from ${exchange.channel.name}: attributes:${\n attributeRequests?.map(path => this.#endpointStructure.resolveAttributeName(path)).join(\", \") ?? \"none\"\n }, events:${\n eventRequests?.map(path => this.#endpointStructure.resolveEventName(path)).join(\", \") ?? \"none\"\n } isFabricFiltered=${isFabricFiltered}`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n if (attributeRequests === undefined && eventRequests === undefined) {\n throw new StatusResponseError(\n \"Only Read requests with attributeRequests or eventRequests are supported right now\",\n StatusCode.UnsupportedRead,\n );\n }\n\n const dataVersionFilterMap = new Map<string, number>(\n dataVersionFilters?.map(({ path, dataVersion }) => [clusterPathToId(path), dataVersion]) ?? [],\n );\n if (dataVersionFilterMap.size > 0) {\n logger.debug(\n `DataVersionFilters: ${Array.from(dataVersionFilterMap.entries())\n .map(([path, version]) => `${path}=${version}`)\n .join(\", \")}`,\n );\n }\n\n const attributeReportsPayload = new Array<AttributeReportPayload>();\n for (const requestPath of attributeRequests ?? []) {\n const attributes = this.#endpointStructure.getAttributes([requestPath]);\n\n // Requested attribute path not found in any cluster server on any endpoint\n if (attributes.length === 0) {\n // TODO Add checks for nodeId -> UnknownNode\n if (!isConcreteAttributePath(requestPath)) {\n // Wildcard path and we do not know any of the attributes: Ignore the error\n logger.debug(\n `Read from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n requestPath,\n )}: ${this.#endpointStructure.resolveAttributeName(requestPath)}: ignore non-existing attribute`,\n );\n } else {\n const { endpointId, clusterId, attributeId } = requestPath;\n // Concrete path, but still unknown for us, so generate the right error status\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteAttributePath(endpointId, clusterId, attributeId);\n throw new InternalError(\n \"validateConcreteAttributePath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Error reading attribute from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveAttributeName(requestPath)}: unsupported path: Status=${\n error.code\n }`,\n );\n attributeReportsPayload.push({\n attributeStatus: { path: requestPath, status: { status: error.code } },\n });\n },\n );\n }\n continue;\n }\n\n // Process all known attributes for the given path\n for (const { path, attribute } of attributes) {\n const { nodeId, endpointId, clusterId } = path;\n\n try {\n const { value, version } = await tryCatchAsync(\n async () =>\n this.readAttribute(\n path,\n attribute,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n ),\n NoAssociatedFabricError,\n async () => {\n // TODO: Remove when we remove legacy API\n // This is not fully correct but should be sufficient for now\n // This is fixed in the new API already, so this error should never throw\n // Fabric scoped attributes are access errors, fabric sensitive attributes are just filtered\n // Assume for now that in this place we only need to handle fabric sensitive case\n if (endpointId === undefined || clusterId === undefined) {\n throw new MatterFlowError(\"Should never happen\");\n }\n const cluster = this.#endpointStructure.getClusterServer(endpointId, clusterId);\n if (cluster === undefined || cluster.datasource == undefined) {\n throw new MatterFlowError(\"Should never happen\");\n }\n return {\n version: cluster.datasource.version,\n value: [],\n };\n },\n );\n\n const versionFilterValue =\n endpointId !== undefined && clusterId !== undefined\n ? dataVersionFilterMap.get(clusterPathToId({ nodeId, endpointId, clusterId }))\n : undefined;\n if (versionFilterValue !== undefined && versionFilterValue === version) {\n logger.debug(\n `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n path,\n )}=${Logger.toJSON(value)} (version=${version}) ignored because of dataVersionFilter`,\n );\n continue;\n }\n\n logger.debug(\n `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n path,\n )}=${Logger.toJSON(value)} (version=${version})`,\n );\n\n const { schema } = attribute;\n attributeReportsPayload.push({\n attributeData: { path, dataVersion: version, payload: value, schema },\n });\n } catch (error) {\n logger.error(\n `Error while reading attribute from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)}:`,\n error,\n );\n if (error instanceof StatusResponseError) {\n // Add StatusResponseErrors, but only when the initial path was concrete, else error are ignored\n if (isConcreteAttributePath(requestPath)) {\n attributeReportsPayload.push({ attributeStatus: { path, status: { status: error.code } } });\n }\n } else {\n throw error;\n }\n }\n }\n }\n\n let eventReportsPayload: undefined | EventReportPayload[];\n if (eventRequests) {\n eventReportsPayload = [];\n for (const requestPath of eventRequests) {\n const events = this.#endpointStructure.getEvents([requestPath]);\n\n // Requested event path not found in any cluster server on any endpoint\n if (events.length === 0) {\n // TODO Add checks for nodeId\n if (!isConcreteEventPath(requestPath)) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(\n requestPath,\n )}: ignore non-existing event`,\n );\n } else {\n const { endpointId, clusterId, eventId } = requestPath;\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteEventPath(endpointId, clusterId, eventId);\n throw new InternalError(\n \"validateConcreteEventPath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Read event from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveEventName(requestPath)}: unsupported path: Status=${\n error.code\n }`,\n );\n eventReportsPayload?.push({\n eventStatus: { path: requestPath, status: { status: error.code } },\n });\n },\n );\n }\n continue;\n }\n\n const reportsForPath = new Array<{ eventData: EventDataPayload }>();\n for (const { path, event } of events) {\n try {\n const { endpointId } = path;\n const matchingEvents = await this.readEvent(\n path,\n eventFilters,\n event,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n );\n logger.debug(\n `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(\n path,\n )}=${Logger.toJSON(matchingEvents)}`,\n );\n const { schema } = event;\n reportsForPath.push(\n ...matchingEvents.map(({ eventNumber, priority, epochTimestamp, data }) => ({\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n payload: data,\n schema,\n },\n })),\n );\n } catch (error) {\n logger.error(\n `Error while reading event from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveEventName(path)}:`,\n error,\n );\n if (error instanceof StatusResponseError) {\n // Add StatusResponseErrors, but only when the initial path was concrete, else error are ignored\n if (isConcreteEventPath(requestPath)) {\n eventReportsPayload?.push({ eventStatus: { path, status: { status: error.code } } });\n }\n } else {\n throw error;\n }\n }\n }\n eventReportsPayload.push(\n ...reportsForPath.sort((a, b) => {\n const eventNumberA = a.eventData?.eventNumber ?? EventNumber(0);\n const eventNumberB = b.eventData?.eventNumber ?? EventNumber(0);\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n }),\n );\n }\n }\n\n // TODO support suppressResponse for responses\n return {\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n suppressResponse: false,\n attributeReportsPayload, // TODO Return compressed response once https://github.com/project-chip/connectedhomeip/issues/29359 is solved\n eventReportsPayload,\n };\n }\n\n protected async readAttribute(\n _path: AttributePath,\n attribute: AnyAttributeServer<any>,\n exchange: MessageExchange<MatterDevice>,\n isFabricFiltered: boolean,\n message: Message,\n _endpoint: EndpointInterface,\n ) {\n return attribute.getWithVersion(exchange.session, isFabricFiltered, message);\n }\n\n protected async readEvent(\n _path: EventPath,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n event: EventServer<any, any>,\n exchange: MessageExchange<MatterDevice>,\n isFabricFiltered: boolean,\n message: Message,\n _endpoint: EndpointInterface,\n ) {\n return event.get(exchange.session, isFabricFiltered, message, eventFilters);\n }\n\n async handleWriteRequest(\n exchange: MessageExchange<MatterDevice>,\n { suppressResponse, timedRequest, writeRequests, interactionModelRevision, moreChunkedMessages }: WriteRequest,\n message: Message,\n ): Promise<WriteResponse> {\n const sessionType = message.packetHeader.sessionType;\n logger.debug(\n `Received write request from ${exchange.channel.name}: ${writeRequests\n .map(req => this.#endpointStructure.resolveAttributeName(req.path))\n .join(\", \")}, suppressResponse=${suppressResponse}, moreChunkedMessages=${moreChunkedMessages}`,\n );\n\n if (moreChunkedMessages && suppressResponse) {\n throw new StatusResponseError(\n \"MoreChunkedMessages and SuppressResponse cannot be used together in write messages\",\n StatusCode.InvalidAction,\n );\n }\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n const receivedWithinTimedInteraction = exchange.hasActiveTimedInteraction();\n\n if (receivedWithinTimedInteraction && moreChunkedMessages) {\n throw new StatusResponseError(\n \"Write Request action that is part of a Timed Write Interaction SHALL NOT be chunked.\",\n StatusCode.InvalidAction,\n );\n }\n\n if (exchange.hasExpiredTimedInteraction()) {\n exchange.clearTimedInteraction(); // ??\n throw new StatusResponseError(`Timed request window expired. Decline write request.`, StatusCode.Timeout);\n }\n\n if (timedRequest !== exchange.hasTimedInteraction()) {\n throw new StatusResponseError(\n `timedRequest flag of write interaction (${timedRequest}) mismatch with expected timed interaction (${receivedWithinTimedInteraction}).`,\n StatusCode.TimedRequestMismatch,\n );\n }\n\n if (receivedWithinTimedInteraction) {\n logger.debug(`Write request from ${exchange.channel.name} received while timed interaction is running.`);\n exchange.clearTimedInteraction();\n if (sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Write requests are only allowed on unicast sessions when a timed interaction is running.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n }\n\n if (sessionType === SessionType.Group && !suppressResponse) {\n throw new StatusResponseError(\n \"Write requests are only allowed as group casts when suppressResponse=true.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n\n const writeData = expandPathsInAttributeData(writeRequests, true);\n\n const writeResults = new Array<{\n path: TypeFromSchema<typeof TlvAttributePath>;\n statusCode: StatusCode;\n clusterStatusCode?: number;\n }>();\n const attributeListWrites = new Set<AttributeServer<any>>();\n const clusterDataVersionInfo = new Map<string, number>();\n const inaccessiblePaths = new Set<string>();\n\n // TODO Add handling for moreChunkedMessages here when adopting for Matter 1.3\n\n for (const writeRequest of writeData) {\n const { path: writePath, dataVersion } = writeRequest;\n const { clusterId, attributeId, listIndex } = writePath;\n\n if (clusterId === undefined) {\n throw new StatusResponseError(\n \"Illegal write request with wildcard cluster ID\",\n StatusCode.InvalidAction,\n );\n }\n\n if (attributeId === undefined) {\n throw new StatusResponseError(\n \"Illegal write request with wildcard attribute ID\",\n StatusCode.InvalidAction,\n );\n }\n\n const attributes = this.#endpointStructure.getAttributes([writePath], true);\n\n // No existing attribute matches the given path and is writable\n if (attributes.length === 0) {\n // TODO: Also check nodeId\n if (!isConcreteAttributePath(writePath)) {\n // Wildcard path: Just ignore\n logger.debug(\n `Write from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n writePath,\n )}: ignore non-existing (wildcard) attribute`,\n );\n } else {\n const { endpointId } = writePath;\n\n // was a concrete path\n tryCatch(\n () => {\n if (\n this.#endpointStructure.validateConcreteAttributePath(\n endpointId,\n clusterId,\n attributeId,\n )\n ) {\n throw new StatusResponseError(\n `Attribute ${attributeId} is not writable.`,\n StatusCode.UnsupportedWrite,\n );\n }\n throw new InternalError(\n \"validateConcreteAttributePath check should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Write from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n writePath,\n )} not allowed: Status=${error.code}`,\n );\n writeResults.push({ path: writePath, statusCode: error.code });\n },\n );\n }\n continue;\n }\n\n // Concrete path and found and writable\n if (attributes.length === 1 && isConcreteAttributePath(writePath)) {\n const { endpointId } = writePath;\n const { attribute } = attributes[0];\n\n // TODO Check ACL here\n\n if (attribute.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This write requires a timed interaction which is not initialized.`);\n writeResults.push({ path: writePath, statusCode: StatusCode.NeedsTimedInteraction });\n continue;\n }\n\n if (\n attribute instanceof FabricScopedAttributeServer &&\n (!exchange.session.isSecure || !(exchange.session as SecureSession<MatterDevice>).fabric)\n ) {\n logger.debug(`This write requires a secure session with a fabric assigned which is missing.`);\n writeResults.push({ path: writePath, statusCode: StatusCode.UnsupportedAccess });\n continue;\n }\n\n // Check the provided dataVersion with the dataVersion of the cluster\n // And remember this initial dataVersion for all checks inside this write transaction to allow proper\n // processing of chunked lists\n if (dataVersion !== undefined) {\n const datasource = this.#endpointStructure.getClusterServer(endpointId, clusterId)?.datasource;\n const { nodeId } = writePath;\n const clusterKey = clusterPathToId({ nodeId, endpointId, clusterId });\n const currentDataVersion = clusterDataVersionInfo.get(clusterKey) ?? datasource?.version;\n\n if (currentDataVersion !== undefined) {\n if (dataVersion !== currentDataVersion) {\n logger.debug(\n `This write requires a specific data version (${dataVersion}) which do not match the current cluster data version (${currentDataVersion}).`,\n );\n writeResults.push({ path: writePath, statusCode: StatusCode.DataVersionMismatch });\n continue;\n }\n clusterDataVersionInfo.set(clusterKey, currentDataVersion);\n }\n }\n }\n\n for (const { path, attribute } of attributes) {\n const { schema, defaultValue } = attribute;\n const pathId = attributePathToId(path);\n\n try {\n if (\n !(attribute instanceof AttributeServer) &&\n !(attribute instanceof FabricScopedAttributeServer)\n ) {\n throw new StatusResponseError(\n \"Fixed attributes cannot be written\",\n StatusCode.UnsupportedWrite,\n );\n }\n\n if (inaccessiblePaths.has(pathId)) {\n logger.debug(`This write is not allowed due to previous access denied.`);\n continue;\n }\n\n const { endpointId } = path;\n const value =\n listIndex === undefined\n ? decodeAttributeValueWithSchema(schema, [writeRequest], defaultValue)\n : decodeListAttributeValueWithSchema(\n schema,\n [writeRequest],\n (\n await this.readAttribute(\n path,\n attribute,\n exchange,\n true,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n )\n ).value ?? defaultValue,\n );\n logger.debug(\n `Handle write request from ${\n exchange.channel.name\n } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(\n value,\n )} (listIndex=${listIndex}, for-version=${dataVersion})`,\n );\n\n if (attribute.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This write requires a timed interaction which is not initialized.`);\n throw new StatusResponseError(\n \"This write requires a timed interaction which is not initialized.\",\n StatusCode.NeedsTimedInteraction,\n );\n }\n\n await this.writeAttribute(\n path,\n attribute,\n value,\n exchange,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n receivedWithinTimedInteraction,\n schema instanceof ArraySchema,\n );\n if (schema instanceof ArraySchema && !attributeListWrites.has(attribute)) {\n attributeListWrites.add(attribute);\n }\n } catch (error: any) {\n if (error instanceof StatusResponseError && error.code === StatusCode.UnsupportedAccess) {\n inaccessiblePaths.add(pathId);\n }\n if (attributes.length === 1 && isConcreteAttributePath(writePath)) {\n // For Multi-Attribute-Writes we ignore errors\n logger.error(\n `Error while handling write request from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)}:`,\n error instanceof StatusResponseError ? error.message : error,\n );\n if (error instanceof StatusResponseError) {\n writeResults.push({ path, statusCode: error.code, clusterStatusCode: error.clusterCode });\n continue;\n }\n writeResults.push({ path, statusCode: StatusCode.ConstraintError });\n continue;\n } else {\n logger.debug(\n `While handling write request from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)} ignored: ${error.message}`,\n );\n\n // TODO - This behavior may be wrong.\n //\n // If a wildcard write fails we should either:\n //\n // 1. Ignore entirely (add nothing to write results), or\n // 2. Add an error response for the concrete attribute that failed.\n //\n // Spec is a little ambiguous. After request path expansion, in core 1.2 8.7.3.2 it states:\n //\n // \"If the path indicates attribute data that is not writable, then the path SHALL be\n // discarded\"\n //\n // So is this \"not writable\" -- so it should be #1 -- or is this \"writable\" but with invalid\n // data? The latter is error case #2 but spec doesn't make clear what the status code would\n // be... We could fall back to CONSTRAINT_ERROR like we do above though\n //\n // Currently what we do is add a success response for every concrete path that fails.\n }\n }\n writeResults.push({ path, statusCode: StatusCode.Success });\n }\n //.filter(({ statusCode }) => statusCode !== StatusCode.Success); // see https://github.com/project-chip/connectedhomeip/issues/26198\n }\n\n const errorResults = writeResults.filter(({ statusCode }) => statusCode !== StatusCode.Success);\n logger.debug(\n `Write request from ${exchange.channel.name} done ${\n errorResults.length\n ? `with following errors: ${errorResults\n .map(\n ({ path, statusCode }) =>\n `${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(statusCode)}`,\n )\n .join(\", \")}`\n : \"without errors\"\n }`,\n );\n\n const response = {\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n writeResponses: writeResults.map(({ path, statusCode, clusterStatusCode }) => ({\n path,\n status: { status: statusCode, clusterStatus: clusterStatusCode },\n })),\n };\n\n // Trigger attribute events for delayed list writes\n for (const attribute of attributeListWrites.values()) {\n try {\n attribute.triggerDelayedChangeEvents();\n } catch (error) {\n logger.error(\n `Ignored Error while writing attribute from ${exchange.channel.name} to ${attribute.name}:`,\n error,\n );\n }\n }\n\n return response;\n }\n\n protected async writeAttribute(\n _path: AttributePath,\n attribute: AttributeServer<any>,\n value: any,\n exchange: MessageExchange<MatterDevice>,\n message: Message,\n _endpoint: EndpointInterface,\n _receivedWithinTimedInteraction?: boolean,\n isListWrite = false,\n ) {\n attribute.set(value, exchange.session, message, isListWrite);\n }\n\n async handleSubscribeRequest(\n exchange: MessageExchange<MatterDevice>,\n {\n minIntervalFloorSeconds,\n maxIntervalCeilingSeconds,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n keepSubscriptions,\n isFabricFiltered,\n interactionModelRevision,\n }: SubscribeRequest,\n messenger: InteractionServerMessenger,\n message: Message,\n ): Promise<void> {\n logger.debug(\n `Received subscribe request from ${exchange.channel.name} (keepSubscriptions=${keepSubscriptions}, isFabricFiltered=${isFabricFiltered})`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n assertSecureSession(exchange.session, \"Subscriptions are only implemented on secure sessions\");\n const session = exchange.session;\n const fabric = session.fabric;\n if (fabric === undefined)\n throw new StatusResponseError(\n \"Subscriptions are only implemented after a fabric has been assigned\",\n StatusCode.InvalidAction,\n );\n\n if (\n (!Array.isArray(attributeRequests) || attributeRequests.length === 0) &&\n (!Array.isArray(eventRequests) || eventRequests.length === 0)\n ) {\n throw new StatusResponseError(\"No attributes or events requested\", StatusCode.InvalidAction);\n }\n\n logger.debug(\n `Subscribe to attributes:${\n attributeRequests?.map(path => this.#endpointStructure.resolveAttributeName(path)).join(\", \") ?? \"none\"\n }, events:${\n eventRequests?.map(path => this.#endpointStructure.resolveEventName(path)).join(\", \") ?? \"none\"\n }`,\n );\n\n if (dataVersionFilters !== undefined && dataVersionFilters.length > 0) {\n logger.debug(\n `DataVersionFilters: ${dataVersionFilters\n .map(\n ({ path: { nodeId, endpointId, clusterId }, dataVersion }) =>\n `${clusterPathToId({ nodeId, endpointId, clusterId })}=${dataVersion}`,\n )\n .join(\", \")}`,\n );\n }\n if (eventFilters !== undefined && eventFilters.length > 0)\n logger.debug(\n `Event filters: ${eventFilters.map(filter => `${filter.nodeId}/${filter.eventMin}`).join(\", \")}`,\n );\n\n if (minIntervalFloorSeconds < 0) {\n throw new StatusResponseError(\n \"minIntervalFloorSeconds should be greater or equal to 0\",\n StatusCode.InvalidAction,\n );\n }\n if (maxIntervalCeilingSeconds < 0) {\n throw new StatusResponseError(\n \"maxIntervalCeilingSeconds should be greater or equal to 1\",\n StatusCode.InvalidAction,\n );\n }\n if (maxIntervalCeilingSeconds < minIntervalFloorSeconds) {\n throw new StatusResponseError(\n \"maxIntervalCeilingSeconds should be greater or equal to minIntervalFloorSeconds\",\n StatusCode.InvalidAction,\n );\n }\n\n // TODO: Interpret specs:\n // The publisher SHALL compute an appropriate value for the MaxInterval field in the action. This SHALL respect the following constraint: MinIntervalFloor \u2264 MaxInterval \u2264 MAX(SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT=60mn, MaxIntervalCeiling)\n\n if (this.#nextSubscriptionId === 0xffffffff) this.#nextSubscriptionId = 0;\n const subscriptionId = this.#nextSubscriptionId++;\n const subscriptionHandler = new SubscriptionHandler(\n subscriptionId,\n session,\n this.#endpointStructure,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n this.#eventHandler,\n isFabricFiltered,\n minIntervalFloorSeconds,\n maxIntervalCeilingSeconds,\n () => this.#subscriptionMap.delete(subscriptionId),\n this.#subscriptionConfig,\n );\n\n try {\n // Send initial data report to prime the subscription with initial data\n await subscriptionHandler.sendInitialReport(\n messenger,\n (path, attribute) =>\n this.readAttribute(\n path,\n attribute,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(path.endpointId)!,\n ),\n (path, event, eventFilters) =>\n this.readEvent(\n path,\n eventFilters,\n event,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(path.endpointId)!,\n ),\n );\n } catch (error: any) {\n logger.error(\n `Subscription ${subscriptionId} for Session ${session.id}: Error while sending initial data reports`,\n error,\n );\n await subscriptionHandler.cancel(); // Cleanup\n if (error instanceof StatusResponseError) {\n logger.info(`Sending status response ${error.code} for interaction error: ${error.message}`);\n await messenger.sendStatus(error.code);\n }\n await messenger.close();\n return; // Make sure to not bubble up the exception\n }\n\n if (!keepSubscriptions) {\n logger.debug(`Clear subscriptions for Session ${session.name} because keepSubscriptions=false`);\n await session.clearSubscriptions(true);\n }\n\n const maxInterval = subscriptionHandler.getMaxInterval();\n logger.info(\n `Successfully created subscription ${subscriptionId} for Session ${\n session.id\n }. Updates: ${minIntervalFloorSeconds} - ${maxIntervalCeilingSeconds} => ${maxInterval} seconds (sendInterval = ${subscriptionHandler.getSendInterval()} seconds)`,\n );\n // Then send the subscription response\n await messenger.send(\n MessageType.SubscribeResponse,\n TlvSubscribeResponse.encode({\n subscriptionId,\n maxInterval,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n }),\n );\n\n this.#subscriptionMap.set(subscriptionId, subscriptionHandler);\n session.addSubscription(subscriptionHandler);\n subscriptionHandler.activateSendingUpdates();\n }\n\n async handleInvokeRequest(\n exchange: MessageExchange<MatterDevice>,\n { invokeRequests, timedRequest, suppressResponse, interactionModelRevision }: InvokeRequest,\n message: Message,\n ): Promise<InvokeResponse> {\n logger.debug(\n `Received invoke request from ${exchange.channel.name}: ${invokeRequests\n .map(({ commandPath: { endpointId, clusterId, commandId } }) =>\n this.#endpointStructure.resolveCommandName({ endpointId, clusterId, commandId }),\n )\n .join(\", \")}, suppressResponse=${suppressResponse}`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n const {\n packetHeader: { sessionType },\n } = message;\n const receivedWithinTimedInteraction = exchange.hasActiveTimedInteraction();\n if (exchange.hasExpiredTimedInteraction()) {\n exchange.clearTimedInteraction(); // ??\n throw new StatusResponseError(`Timed request window expired. Decline invoke request.`, StatusCode.Timeout);\n }\n\n if (timedRequest !== exchange.hasTimedInteraction()) {\n throw new StatusResponseError(\n `timedRequest flag of invoke interaction (${timedRequest}) mismatch with expected timed interaction (${receivedWithinTimedInteraction}).`,\n StatusCode.TimedRequestMismatch,\n );\n }\n\n if (receivedWithinTimedInteraction) {\n logger.debug(`Invoke request from ${exchange.channel.name} received while timed interaction is running.`);\n exchange.clearTimedInteraction();\n if (sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Invoke requests are only allowed on unicast sessions when a timed interaction is running.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n }\n\n if (invokeRequests.length > 1) {\n throw new StatusResponseError(\"Multi-command invoke requests are not supported\", StatusCode.InvalidAction);\n }\n\n const invokeResponses: TypeFromSchema<typeof TlvInvokeResponseData>[] = [];\n\n await Promise.all(\n invokeRequests.flatMap(async ({ commandPath, commandFields }) => {\n const commands = this.#endpointStructure.getCommands([commandPath]);\n\n // TODO also check ACL and Timed, Fabric scoping constrains\n\n if (commands.length === 0) {\n // TODO Also check nodeId\n if (!isConcreteCommandPath(commandPath)) {\n // Wildcard path: Just ignore\n logger.debug(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n commandPath,\n )} ignore non-existing attribute`,\n );\n } else {\n const { endpointId, clusterId, commandId } = commandPath;\n invokeResponses.push(\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteCommandPath(\n endpointId,\n clusterId,\n commandId,\n );\n throw new InternalError(\n \"validateConcreteCommandPath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Invoke from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveCommandName(\n commandPath,\n )} unsupported path: Status=${error.code}`,\n );\n return { status: { commandPath, status: { status: error.code } } };\n },\n ),\n );\n }\n return;\n }\n\n for (const { command, path } of commands) {\n const { endpointId } = path;\n if (endpointId === undefined) {\n // Should never happen\n logger.error(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n path,\n )} invalid path because empty endpoint!`,\n );\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.UnsupportedEndpoint } },\n });\n continue;\n }\n const endpoint = this.#endpointStructure.getEndpoint(endpointId);\n if (endpoint === undefined) {\n // Should never happen\n logger.error(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n path,\n )} invalid path because endpoint not found!`,\n );\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.UnsupportedEndpoint } },\n });\n continue;\n }\n if (command.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This invoke requires a timed interaction which is not initialized.`);\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.NeedsTimedInteraction } },\n });\n continue;\n }\n\n const result = await tryCatchAsync(\n async () =>\n await this.invokeCommand(\n path,\n command,\n exchange,\n commandFields ?? TlvNoArguments.encodeTlv(commandFields),\n message,\n endpoint,\n receivedWithinTimedInteraction,\n ),\n StatusResponseError,\n async error => {\n const errorLogText = `Error ${Diagnostic.hex(error.code)}${\n error.clusterCode !== undefined ? `/${Diagnostic.hex(error.clusterCode)}` : \"\"\n } while invoking command: ${error.message}`;\n if (error instanceof ValidationError) {\n logger.info(\n `Validation-${errorLogText}${error.fieldName !== undefined ? ` in field ${error.fieldName}` : \"\"}`,\n );\n } else {\n logger.info(errorLogText);\n }\n return {\n code: error.code,\n clusterCode: error.clusterCode,\n responseId: command.responseId,\n response: TlvNoResponse.encodeTlv(),\n };\n },\n );\n const { code, clusterCode, responseId, response } = result;\n if (response.length === 0) {\n invokeResponses.push({\n status: { commandPath: path, status: { status: code, clusterStatus: clusterCode } },\n });\n } else {\n invokeResponses.push({\n command: {\n commandPath: { ...path, commandId: responseId },\n commandFields: response,\n },\n });\n }\n }\n }),\n );\n\n // TODO support suppressResponse for responses\n return {\n suppressResponse: false,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n invokeResponses,\n };\n }\n\n protected async invokeCommand(\n _path: CommandPath,\n command: CommandServer<any, any>,\n exchange: MessageExchange<MatterDevice>,\n commandFields: any,\n message: Message,\n endpoint: EndpointInterface,\n _receivedWithinTimedInteraction = false,\n ) {\n return command.invoke(exchange.session, commandFields, message, endpoint);\n }\n\n handleTimedRequest(exchange: MessageExchange<MatterDevice>, { timeout, interactionModelRevision }: TimedRequest) {\n logger.debug(`Received timed request (${timeout}ms) from ${exchange.channel.name}`);\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n exchange.startTimedInteraction(timeout);\n }\n\n async close() {\n this.#isClosing = true;\n for (const subscription of this.#subscriptionMap.values()) {\n await subscription.cancel(true);\n }\n }\n}\n\nexport namespace InteractionServer {\n export interface Configuration {\n readonly subscriptionOptions?: SubscriptionOptions;\n readonly eventHandler: EventHandler;\n readonly endpointStructure: InteractionEndpointStructure;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { MatterDevice } from \"../../MatterDevice.js\";\nimport { TlvNoResponse } from \"../../cluster/Cluster.js\";\nimport {\n AnyAttributeServer,\n AttributeServer,\n FabricScopedAttributeServer,\n} from \"../../cluster/server/AttributeServer.js\";\nimport { CommandServer } from \"../../cluster/server/CommandServer.js\";\nimport { EventServer } from \"../../cluster/server/EventServer.js\";\nimport { Message, SessionType } from \"../../codec/MessageCodec.js\";\nimport { InternalError, MatterFlowError } from \"../../common/MatterError.js\";\nimport { tryCatch, tryCatchAsync } from \"../../common/TryCatchHandler.js\";\nimport { ValidationError } from \"../../common/ValidationError.js\";\nimport { Crypto } from \"../../crypto/Crypto.js\";\nimport { AttributeId } from \"../../datatype/AttributeId.js\";\nimport { ClusterId } from \"../../datatype/ClusterId.js\";\nimport { CommandId } from \"../../datatype/CommandId.js\";\nimport { EndpointNumber } from \"../../datatype/EndpointNumber.js\";\nimport { EventId } from \"../../datatype/EventId.js\";\nimport { EventNumber } from \"../../datatype/EventNumber.js\";\nimport { NodeId } from \"../../datatype/NodeId.js\";\nimport { EndpointInterface } from \"../../endpoint/EndpointInterface.js\";\nimport { Diagnostic } from \"../../log/Diagnostic.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { GLOBAL_IDS } from \"../../model/index.js\";\nimport { MessageExchange } from \"../../protocol/MessageExchange.js\";\nimport { ProtocolHandler } from \"../../protocol/ProtocolHandler.js\";\nimport { EventHandler } from \"../../protocol/interaction/EventHandler.js\";\nimport { NoAssociatedFabricError, SecureSession, assertSecureSession } from \"../../session/SecureSession.js\";\nimport { ArraySchema } from \"../../tlv/TlvArray.js\";\nimport { TlvNoArguments } from \"../../tlv/TlvNoArguments.js\";\nimport { TypeFromSchema } from \"../../tlv/TlvSchema.js\";\nimport {\n decodeAttributeValueWithSchema,\n decodeListAttributeValueWithSchema,\n expandPathsInAttributeData,\n} from \"./AttributeDataDecoder.js\";\nimport {\n AttributeReportPayload,\n DataReportPayload,\n EventDataPayload,\n EventReportPayload,\n} from \"./AttributeDataEncoder.js\";\nimport { InteractionEndpointStructure } from \"./InteractionEndpointStructure.js\";\nimport {\n InteractionRecipient,\n InteractionServerMessenger,\n InvokeRequest,\n InvokeResponse,\n MessageType,\n ReadRequest,\n SubscribeRequest,\n TimedRequest,\n WriteRequest,\n WriteResponse,\n} from \"./InteractionMessenger.js\";\nimport {\n TlvAttributePath,\n TlvClusterPath,\n TlvCommandPath,\n TlvEventFilter,\n TlvEventPath,\n TlvInvokeResponseData,\n TlvSubscribeResponse,\n} from \"./InteractionProtocol.js\";\nimport { StatusCode, StatusResponseError } from \"./StatusCode.js\";\nimport { SubscriptionHandler } from \"./SubscriptionHandler.js\";\nimport { SubscriptionOptions } from \"./SubscriptionOptions.js\";\n\n/** Protocol ID for the Interaction Protocol as per Matter specification. */\nexport const INTERACTION_PROTOCOL_ID = 0x0001;\n\n/** Backward compatible re-export for Interaction Model version we support currently. */\nexport const INTERACTION_MODEL_REVISION = 11;\n\n/** Number of Invoke Path setting from our Interaction model implementation. */\nexport const MAX_PATHS_PER_INVOKE = 1;\n\nconst logger = Logger.get(\"InteractionServer\");\n\nexport interface CommandPath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n commandId: CommandId;\n}\n\nexport interface AttributePath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n attributeId: AttributeId;\n}\n\nexport interface EventPath {\n nodeId?: NodeId;\n endpointId: EndpointNumber;\n clusterId: ClusterId;\n eventId: EventId;\n}\n\nexport interface AttributeWithPath {\n path: AttributePath;\n attribute: AnyAttributeServer<any>;\n}\n\nexport interface EventWithPath {\n path: EventPath;\n event: EventServer<any, any>;\n}\n\nexport interface CommandWithPath {\n path: CommandPath;\n command: CommandServer<any, any>;\n}\n\nexport function genericElementPathToId(\n endpointId: EndpointNumber | undefined,\n clusterId: ClusterId | undefined,\n elementId: number | undefined,\n) {\n return `${endpointId}/${clusterId}/${elementId}`;\n}\n\nexport function commandPathToId({ endpointId, clusterId, commandId }: CommandPath) {\n return genericElementPathToId(endpointId, clusterId, commandId);\n}\n\nexport function attributePathToId({ endpointId, clusterId, attributeId }: TypeFromSchema<typeof TlvAttributePath>) {\n return genericElementPathToId(endpointId, clusterId, attributeId);\n}\n\nexport function eventPathToId({ endpointId, clusterId, eventId }: TypeFromSchema<typeof TlvEventPath>) {\n return genericElementPathToId(endpointId, clusterId, eventId);\n}\n\nexport function clusterPathToId({ nodeId, endpointId, clusterId }: TypeFromSchema<typeof TlvClusterPath>) {\n return `${nodeId}/${endpointId}/${clusterId}`;\n}\n\nfunction isConcreteAttributePath(\n path: TypeFromSchema<typeof TlvAttributePath>,\n): path is TypeFromSchema<typeof TlvAttributePath> & AttributePath {\n const { endpointId, clusterId, attributeId } = path;\n return endpointId !== undefined && clusterId !== undefined && attributeId !== undefined;\n}\n\nexport function validateReadAttributesPath(path: TypeFromSchema<typeof TlvAttributePath>, isGroupSession = false) {\n if (isGroupSession) {\n throw new StatusResponseError(\"Illegal read request with group session\", StatusCode.InvalidAction);\n }\n const { clusterId, attributeId } = path;\n if (clusterId === undefined && attributeId !== undefined) {\n if (!GLOBAL_IDS.has(attributeId)) {\n throw new StatusResponseError(\n `Illegal read request for wildcard cluster and non global attribute ${attributeId}`,\n StatusCode.InvalidAction,\n );\n }\n }\n}\n\nfunction validateWriteAttributesPath(path: TypeFromSchema<typeof TlvAttributePath>, isGroupSession = false) {\n const { endpointId, clusterId, attributeId } = path;\n if (clusterId === undefined || attributeId === undefined) {\n throw new StatusResponseError(\n \"Illegal write request with wildcard cluster or attribute ID\",\n StatusCode.InvalidAction,\n );\n }\n if (isGroupSession && endpointId !== undefined) {\n throw new StatusResponseError(\"Illegal write request with group ID and endpoint ID\", StatusCode.InvalidAction);\n }\n}\n\nfunction isConcreteEventPath(\n path: TypeFromSchema<typeof TlvEventPath>,\n): path is TypeFromSchema<typeof TlvEventPath> & EventPath {\n const { endpointId, clusterId, eventId } = path;\n return endpointId !== undefined && clusterId !== undefined && eventId !== undefined;\n}\n\nexport function validateReadEventPath(path: TypeFromSchema<typeof TlvEventPath>, isGroupSession = false) {\n const { clusterId, eventId } = path;\n if (clusterId === undefined && eventId !== undefined) {\n throw new StatusResponseError(\"Illegal read request with wildcard cluster ID\", StatusCode.InvalidAction);\n }\n if (isGroupSession) {\n throw new StatusResponseError(\"Illegal read request with group session\", StatusCode.InvalidAction);\n }\n}\n\nfunction isConcreteCommandPath(\n path: TypeFromSchema<typeof TlvCommandPath>,\n): path is TypeFromSchema<typeof TlvCommandPath> & CommandPath {\n const { endpointId, clusterId, commandId } = path;\n return endpointId !== undefined && clusterId !== undefined && commandId !== undefined;\n}\n\nfunction validateCommandPath(path: TypeFromSchema<typeof TlvCommandPath>, isGroupSession = false) {\n const { endpointId, clusterId, commandId } = path;\n if (clusterId === undefined || commandId === undefined) {\n throw new StatusResponseError(\n \"Illegal write request with wildcard cluster or attribute ID\",\n StatusCode.InvalidAction,\n );\n }\n if (isGroupSession && endpointId !== undefined) {\n throw new StatusResponseError(\"Illegal write request with group ID and endpoint ID\", StatusCode.InvalidAction);\n }\n}\n\n/**\n * Translates interactions from the Matter protocol to Matter.js APIs.\n */\nexport class InteractionServer implements ProtocolHandler<MatterDevice>, InteractionRecipient {\n #endpointStructure;\n #nextSubscriptionId = Crypto.getRandomUInt32();\n readonly #subscriptionMap = new Map<number, SubscriptionHandler>();\n #isClosing = false;\n #subscriptionConfig: SubscriptionOptions.Configuration;\n #eventHandler: EventHandler;\n\n constructor({ subscriptionOptions, eventHandler, endpointStructure }: InteractionServer.Configuration) {\n this.#subscriptionConfig = SubscriptionOptions.configurationFor(subscriptionOptions);\n this.#eventHandler = eventHandler;\n this.#endpointStructure = endpointStructure;\n\n this.#endpointStructure.change.on(() => {\n for (const subscription of this.#subscriptionMap.values()) {\n subscription.updateSubscription();\n }\n });\n }\n\n getId() {\n return INTERACTION_PROTOCOL_ID;\n }\n\n protected get isClosing() {\n return this.#isClosing;\n }\n\n async onNewExchange(exchange: MessageExchange<MatterDevice>) {\n // Note - changes here must be copied to TransactionalInteractionServer as it does not call super() to avoid\n // the stack frame\n if (this.#isClosing) return; // We are closing, ignore anything newly incoming\n await new InteractionServerMessenger(exchange).handleRequest(this);\n }\n\n async handleReadRequest(\n exchange: MessageExchange<MatterDevice>,\n {\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n isFabricFiltered,\n interactionModelRevision,\n }: ReadRequest,\n message: Message,\n ): Promise<DataReportPayload> {\n logger.debug(\n `Received read request from ${exchange.channel.name}: attributes:${\n attributeRequests?.map(path => this.#endpointStructure.resolveAttributeName(path)).join(\", \") ?? \"none\"\n }, events:${\n eventRequests?.map(path => this.#endpointStructure.resolveEventName(path)).join(\", \") ?? \"none\"\n } isFabricFiltered=${isFabricFiltered}`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n if (attributeRequests === undefined && eventRequests === undefined) {\n throw new StatusResponseError(\n \"Only Read requests with attributeRequests or eventRequests are supported right now\",\n StatusCode.UnsupportedRead,\n );\n }\n\n if (message.packetHeader.sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Subscriptions are only allowed on unicast sessions\",\n StatusCode.InvalidAction,\n );\n }\n\n const dataVersionFilterMap = new Map<string, number>(\n dataVersionFilters?.map(({ path, dataVersion }) => [clusterPathToId(path), dataVersion]) ?? [],\n );\n if (dataVersionFilterMap.size > 0) {\n logger.debug(\n `DataVersionFilters: ${Array.from(dataVersionFilterMap.entries())\n .map(([path, version]) => `${path}=${version}`)\n .join(\", \")}`,\n );\n }\n\n const attributeReportsPayload = new Array<AttributeReportPayload>();\n for (const requestPath of attributeRequests ?? []) {\n validateReadAttributesPath(requestPath);\n\n const attributes = this.#endpointStructure.getAttributes([requestPath]);\n\n // Requested attribute path not found in any cluster server on any endpoint\n if (attributes.length === 0) {\n // TODO Add checks for nodeId -> UnknownNode\n if (!isConcreteAttributePath(requestPath)) {\n // Wildcard path and we do not know any of the attributes: Ignore the error\n logger.debug(\n `Read from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n requestPath,\n )}: ${this.#endpointStructure.resolveAttributeName(requestPath)}: ignore non-existing attribute`,\n );\n } else {\n const { endpointId, clusterId, attributeId } = requestPath;\n // Concrete path, but still unknown for us, so generate the right error status\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteAttributePath(endpointId, clusterId, attributeId);\n throw new InternalError(\n \"validateConcreteAttributePath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Error reading attribute from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveAttributeName(requestPath)}: unsupported path: Status=${\n error.code\n }`,\n );\n attributeReportsPayload.push({\n attributeStatus: { path: requestPath, status: { status: error.code } },\n });\n },\n );\n }\n continue;\n }\n\n // Process all known attributes for the given path\n for (const { path, attribute } of attributes) {\n const { nodeId, endpointId, clusterId } = path;\n\n try {\n const { value, version } = await tryCatchAsync(\n async () =>\n this.readAttribute(\n path,\n attribute,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n ),\n NoAssociatedFabricError,\n async () => {\n // TODO: Remove when we remove legacy API\n // This is not fully correct but should be sufficient for now\n // This is fixed in the new API already, so this error should never throw\n // Fabric scoped attributes are access errors, fabric sensitive attributes are just filtered\n // Assume for now that in this place we only need to handle fabric sensitive case\n if (endpointId === undefined || clusterId === undefined) {\n throw new MatterFlowError(\"Should never happen\");\n }\n const cluster = this.#endpointStructure.getClusterServer(endpointId, clusterId);\n if (cluster === undefined || cluster.datasource == undefined) {\n throw new MatterFlowError(\"Should never happen\");\n }\n return {\n version: cluster.datasource.version,\n value: [],\n };\n },\n );\n\n const versionFilterValue =\n endpointId !== undefined && clusterId !== undefined\n ? dataVersionFilterMap.get(clusterPathToId({ nodeId, endpointId, clusterId }))\n : undefined;\n if (versionFilterValue !== undefined && versionFilterValue === version) {\n logger.debug(\n `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n path,\n )}=${Logger.toJSON(value)} (version=${version}) ignored because of dataVersionFilter`,\n );\n continue;\n }\n\n logger.debug(\n `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n path,\n )}=${Logger.toJSON(value)} (version=${version})`,\n );\n\n const { schema } = attribute;\n attributeReportsPayload.push({\n attributeData: { path, dataVersion: version, payload: value, schema },\n });\n } catch (error) {\n logger.error(\n `Error while reading attribute from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)}:`,\n error,\n );\n if (error instanceof StatusResponseError) {\n // Add StatusResponseErrors, but only when the initial path was concrete, else error are ignored\n if (isConcreteAttributePath(requestPath)) {\n attributeReportsPayload.push({ attributeStatus: { path, status: { status: error.code } } });\n }\n } else {\n throw error;\n }\n }\n }\n }\n\n let eventReportsPayload: undefined | EventReportPayload[];\n if (eventRequests) {\n eventReportsPayload = [];\n for (const requestPath of eventRequests) {\n validateReadEventPath(requestPath);\n\n const events = this.#endpointStructure.getEvents([requestPath]);\n\n // Requested event path not found in any cluster server on any endpoint\n if (events.length === 0) {\n // TODO Add checks for nodeId\n if (!isConcreteEventPath(requestPath)) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(\n requestPath,\n )}: ignore non-existing event`,\n );\n } else {\n const { endpointId, clusterId, eventId } = requestPath;\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteEventPath(endpointId, clusterId, eventId);\n throw new InternalError(\n \"validateConcreteEventPath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Read event from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveEventName(requestPath)}: unsupported path: Status=${\n error.code\n }`,\n );\n eventReportsPayload?.push({\n eventStatus: { path: requestPath, status: { status: error.code } },\n });\n },\n );\n }\n continue;\n }\n\n const reportsForPath = new Array<{ eventData: EventDataPayload }>();\n for (const { path, event } of events) {\n try {\n const { endpointId } = path;\n const matchingEvents = await this.readEvent(\n path,\n eventFilters,\n event,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n );\n logger.debug(\n `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(\n path,\n )}=${Logger.toJSON(matchingEvents)}`,\n );\n const { schema } = event;\n reportsForPath.push(\n ...matchingEvents.map(({ eventNumber, priority, epochTimestamp, data }) => ({\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n payload: data,\n schema,\n },\n })),\n );\n } catch (error) {\n logger.error(\n `Error while reading event from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveEventName(path)}:`,\n error,\n );\n if (error instanceof StatusResponseError) {\n // Add StatusResponseErrors, but only when the initial path was concrete, else error are ignored\n if (isConcreteEventPath(requestPath)) {\n eventReportsPayload?.push({ eventStatus: { path, status: { status: error.code } } });\n }\n } else {\n throw error;\n }\n }\n }\n eventReportsPayload.push(\n ...reportsForPath.sort((a, b) => {\n const eventNumberA = a.eventData?.eventNumber ?? EventNumber(0);\n const eventNumberB = b.eventData?.eventNumber ?? EventNumber(0);\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n }),\n );\n }\n }\n\n // TODO support suppressResponse for responses\n return {\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n suppressResponse: false,\n attributeReportsPayload, // TODO Return compressed response once https://github.com/project-chip/connectedhomeip/issues/29359 is solved\n eventReportsPayload,\n };\n }\n\n protected async readAttribute(\n _path: AttributePath,\n attribute: AnyAttributeServer<any>,\n exchange: MessageExchange<MatterDevice>,\n isFabricFiltered: boolean,\n message: Message,\n _endpoint: EndpointInterface,\n ) {\n return attribute.getWithVersion(exchange.session, isFabricFiltered, message);\n }\n\n protected async readEvent(\n _path: EventPath,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n event: EventServer<any, any>,\n exchange: MessageExchange<MatterDevice>,\n isFabricFiltered: boolean,\n message: Message,\n _endpoint: EndpointInterface,\n ) {\n return event.get(exchange.session, isFabricFiltered, message, eventFilters);\n }\n\n async handleWriteRequest(\n exchange: MessageExchange<MatterDevice>,\n { suppressResponse, timedRequest, writeRequests, interactionModelRevision, moreChunkedMessages }: WriteRequest,\n message: Message,\n ): Promise<WriteResponse> {\n const sessionType = message.packetHeader.sessionType;\n logger.debug(\n `Received write request from ${exchange.channel.name}: ${writeRequests\n .map(req => this.#endpointStructure.resolveAttributeName(req.path))\n .join(\", \")}, suppressResponse=${suppressResponse}, moreChunkedMessages=${moreChunkedMessages}`,\n );\n\n if (moreChunkedMessages && suppressResponse) {\n throw new StatusResponseError(\n \"MoreChunkedMessages and SuppressResponse cannot be used together in write messages\",\n StatusCode.InvalidAction,\n );\n }\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n const receivedWithinTimedInteraction = exchange.hasActiveTimedInteraction();\n\n if (receivedWithinTimedInteraction && moreChunkedMessages) {\n throw new StatusResponseError(\n \"Write Request action that is part of a Timed Write Interaction SHALL NOT be chunked.\",\n StatusCode.InvalidAction,\n );\n }\n\n if (exchange.hasExpiredTimedInteraction()) {\n exchange.clearTimedInteraction(); // ??\n throw new StatusResponseError(`Timed request window expired. Decline write request.`, StatusCode.Timeout);\n }\n\n if (timedRequest !== exchange.hasTimedInteraction()) {\n throw new StatusResponseError(\n `timedRequest flag of write interaction (${timedRequest}) mismatch with expected timed interaction (${receivedWithinTimedInteraction}).`,\n StatusCode.TimedRequestMismatch,\n );\n }\n\n if (receivedWithinTimedInteraction) {\n logger.debug(`Write request from ${exchange.channel.name} received while timed interaction is running.`);\n exchange.clearTimedInteraction();\n if (sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Write requests are only allowed on unicast sessions when a timed interaction is running.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n }\n\n if (sessionType === SessionType.Group && !suppressResponse) {\n throw new StatusResponseError(\n \"Write requests are only allowed as group casts when suppressResponse=true.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n\n const writeData = expandPathsInAttributeData(writeRequests, true);\n\n const writeResults = new Array<{\n path: TypeFromSchema<typeof TlvAttributePath>;\n statusCode: StatusCode;\n clusterStatusCode?: number;\n }>();\n const attributeListWrites = new Set<AttributeServer<any>>();\n const clusterDataVersionInfo = new Map<string, number>();\n const inaccessiblePaths = new Set<string>();\n\n // TODO Add handling for moreChunkedMessages here when adopting for Matter 1.3\n\n for (const writeRequest of writeData) {\n const { path: writePath, dataVersion } = writeRequest;\n const { listIndex } = writePath;\n\n validateWriteAttributesPath(writePath);\n\n const attributes = this.#endpointStructure.getAttributes([writePath], true);\n\n // No existing attribute matches the given path and is writable\n if (attributes.length === 0) {\n // TODO: Also check nodeId\n if (!isConcreteAttributePath(writePath)) {\n // Wildcard path: Just ignore\n logger.debug(\n `Write from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n writePath,\n )}: ignore non-existing (wildcard) attribute`,\n );\n } else {\n const { endpointId, clusterId, attributeId } = writePath;\n\n // was a concrete path\n tryCatch(\n () => {\n if (\n this.#endpointStructure.validateConcreteAttributePath(\n endpointId,\n clusterId,\n attributeId,\n )\n ) {\n throw new StatusResponseError(\n `Attribute ${attributeId} is not writable.`,\n StatusCode.UnsupportedWrite,\n );\n }\n throw new InternalError(\n \"validateConcreteAttributePath check should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Write from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(\n writePath,\n )} not allowed: Status=${error.code}`,\n );\n writeResults.push({ path: writePath, statusCode: error.code });\n },\n );\n }\n continue;\n }\n\n // Concrete path and found and writable\n if (attributes.length === 1 && isConcreteAttributePath(writePath)) {\n const { endpointId, clusterId } = writePath;\n const { attribute } = attributes[0];\n\n if (attribute.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This write requires a timed interaction which is not initialized.`);\n writeResults.push({ path: writePath, statusCode: StatusCode.NeedsTimedInteraction });\n continue;\n }\n\n if (\n attribute instanceof FabricScopedAttributeServer &&\n (!exchange.session.isSecure || !(exchange.session as SecureSession<MatterDevice>).fabric)\n ) {\n logger.debug(`This write requires a secure session with a fabric assigned which is missing.`);\n writeResults.push({ path: writePath, statusCode: StatusCode.UnsupportedAccess });\n continue;\n }\n\n // Check the provided dataVersion with the dataVersion of the cluster\n // And remember this initial dataVersion for all checks inside this write transaction to allow proper\n // processing of chunked lists\n if (dataVersion !== undefined) {\n const datasource = this.#endpointStructure.getClusterServer(endpointId, clusterId)?.datasource;\n const { nodeId } = writePath;\n const clusterKey = clusterPathToId({ nodeId, endpointId, clusterId });\n const currentDataVersion = clusterDataVersionInfo.get(clusterKey) ?? datasource?.version;\n\n if (currentDataVersion !== undefined) {\n if (dataVersion !== currentDataVersion) {\n logger.debug(\n `This write requires a specific data version (${dataVersion}) which do not match the current cluster data version (${currentDataVersion}).`,\n );\n writeResults.push({ path: writePath, statusCode: StatusCode.DataVersionMismatch });\n continue;\n }\n clusterDataVersionInfo.set(clusterKey, currentDataVersion);\n }\n }\n }\n\n for (const { path, attribute } of attributes) {\n const { schema, defaultValue } = attribute;\n const pathId = attributePathToId(path);\n\n try {\n if (\n !(attribute instanceof AttributeServer) &&\n !(attribute instanceof FabricScopedAttributeServer)\n ) {\n throw new StatusResponseError(\n \"Fixed attributes cannot be written\",\n StatusCode.UnsupportedWrite,\n );\n }\n\n if (inaccessiblePaths.has(pathId)) {\n logger.debug(`This write is not allowed due to previous access denied.`);\n continue;\n }\n\n const { endpointId } = path;\n const value =\n listIndex === undefined\n ? decodeAttributeValueWithSchema(schema, [writeRequest], defaultValue)\n : decodeListAttributeValueWithSchema(\n schema,\n [writeRequest],\n (\n await this.readAttribute(\n path,\n attribute,\n exchange,\n true,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n )\n ).value ?? defaultValue,\n );\n logger.debug(\n `Handle write request from ${\n exchange.channel.name\n } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(\n value,\n )} (listIndex=${listIndex}, for-version=${dataVersion})`,\n );\n\n if (attribute.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This write requires a timed interaction which is not initialized.`);\n throw new StatusResponseError(\n \"This write requires a timed interaction which is not initialized.\",\n StatusCode.NeedsTimedInteraction,\n );\n }\n\n await this.writeAttribute(\n path,\n attribute,\n value,\n exchange,\n message,\n this.#endpointStructure.getEndpoint(endpointId)!,\n receivedWithinTimedInteraction,\n schema instanceof ArraySchema,\n );\n if (schema instanceof ArraySchema && !attributeListWrites.has(attribute)) {\n attributeListWrites.add(attribute);\n }\n } catch (error: any) {\n if (error instanceof StatusResponseError && error.code === StatusCode.UnsupportedAccess) {\n inaccessiblePaths.add(pathId);\n }\n if (attributes.length === 1 && isConcreteAttributePath(writePath)) {\n // For Multi-Attribute-Writes we ignore errors\n logger.error(\n `Error while handling write request from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)}:`,\n error instanceof StatusResponseError ? error.message : error,\n );\n if (error instanceof StatusResponseError) {\n writeResults.push({ path, statusCode: error.code, clusterStatusCode: error.clusterCode });\n continue;\n }\n writeResults.push({ path, statusCode: StatusCode.ConstraintError });\n continue;\n } else {\n logger.debug(\n `While handling write request from ${\n exchange.channel.name\n } to ${this.#endpointStructure.resolveAttributeName(path)} ignored: ${error.message}`,\n );\n\n // TODO - This behavior may be wrong.\n //\n // If a wildcard write fails we should either:\n //\n // 1. Ignore entirely (add nothing to write results), or\n // 2. Add an error response for the concrete attribute that failed.\n //\n // Spec is a little ambiguous. After request path expansion, in core 1.2 8.7.3.2 it states:\n //\n // \"If the path indicates attribute data that is not writable, then the path SHALL be\n // discarded\"\n //\n // So is this \"not writable\" -- so it should be #1 -- or is this \"writable\" but with invalid\n // data? The latter is error case #2 but spec doesn't make clear what the status code would\n // be... We could fall back to CONSTRAINT_ERROR like we do above though\n //\n // Currently what we do is add a success response for every concrete path that fails.\n }\n }\n writeResults.push({ path, statusCode: StatusCode.Success });\n }\n //.filter(({ statusCode }) => statusCode !== StatusCode.Success); // see https://github.com/project-chip/connectedhomeip/issues/26198\n }\n\n const errorResults = writeResults.filter(({ statusCode }) => statusCode !== StatusCode.Success);\n logger.debug(\n `Write request from ${exchange.channel.name} done ${\n errorResults.length\n ? `with following errors: ${errorResults\n .map(\n ({ path, statusCode }) =>\n `${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(statusCode)}`,\n )\n .join(\", \")}`\n : \"without errors\"\n }`,\n );\n\n const response = {\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n writeResponses: writeResults.map(({ path, statusCode, clusterStatusCode }) => ({\n path,\n status: { status: statusCode, clusterStatus: clusterStatusCode },\n })),\n };\n\n // Trigger attribute events for delayed list writes\n for (const attribute of attributeListWrites.values()) {\n try {\n attribute.triggerDelayedChangeEvents();\n } catch (error) {\n logger.error(\n `Ignored Error while writing attribute from ${exchange.channel.name} to ${attribute.name}:`,\n error,\n );\n }\n }\n\n return response;\n }\n\n protected async writeAttribute(\n _path: AttributePath,\n attribute: AttributeServer<any>,\n value: any,\n exchange: MessageExchange<MatterDevice>,\n message: Message,\n _endpoint: EndpointInterface,\n _receivedWithinTimedInteraction?: boolean,\n isListWrite = false,\n ) {\n attribute.set(value, exchange.session, message, isListWrite);\n }\n\n async handleSubscribeRequest(\n exchange: MessageExchange<MatterDevice>,\n {\n minIntervalFloorSeconds,\n maxIntervalCeilingSeconds,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n keepSubscriptions,\n isFabricFiltered,\n interactionModelRevision,\n }: SubscribeRequest,\n messenger: InteractionServerMessenger,\n message: Message,\n ): Promise<void> {\n logger.debug(\n `Received subscribe request from ${exchange.channel.name} (keepSubscriptions=${keepSubscriptions}, isFabricFiltered=${isFabricFiltered})`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n if (message.packetHeader.sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Subscriptions are only allowed on unicast sessions\",\n StatusCode.InvalidAction,\n );\n }\n\n assertSecureSession(exchange.session, \"Subscriptions are only implemented on secure sessions\");\n const session = exchange.session;\n const fabric = session.fabric;\n if (fabric === undefined)\n throw new StatusResponseError(\n \"Subscriptions are only implemented after a fabric has been assigned\",\n StatusCode.InvalidAction,\n );\n\n if (\n (!Array.isArray(attributeRequests) || attributeRequests.length === 0) &&\n (!Array.isArray(eventRequests) || eventRequests.length === 0)\n ) {\n throw new StatusResponseError(\"No attributes or events requested\", StatusCode.InvalidAction);\n }\n\n logger.debug(\n `Subscribe to attributes:${\n attributeRequests?.map(path => this.#endpointStructure.resolveAttributeName(path)).join(\", \") ?? \"none\"\n }, events:${\n eventRequests?.map(path => this.#endpointStructure.resolveEventName(path)).join(\", \") ?? \"none\"\n }`,\n );\n\n if (dataVersionFilters !== undefined && dataVersionFilters.length > 0) {\n logger.debug(\n `DataVersionFilters: ${dataVersionFilters\n .map(\n ({ path: { nodeId, endpointId, clusterId }, dataVersion }) =>\n `${clusterPathToId({ nodeId, endpointId, clusterId })}=${dataVersion}`,\n )\n .join(\", \")}`,\n );\n }\n if (eventFilters !== undefined && eventFilters.length > 0)\n logger.debug(\n `Event filters: ${eventFilters.map(filter => `${filter.nodeId}/${filter.eventMin}`).join(\", \")}`,\n );\n\n // Validate of the paths before proceeding\n attributeRequests?.forEach(path => validateReadAttributesPath(path));\n eventRequests?.forEach(path => validateReadEventPath(path));\n\n if (minIntervalFloorSeconds < 0) {\n throw new StatusResponseError(\n \"minIntervalFloorSeconds should be greater or equal to 0\",\n StatusCode.InvalidAction,\n );\n }\n if (maxIntervalCeilingSeconds < 0) {\n throw new StatusResponseError(\n \"maxIntervalCeilingSeconds should be greater or equal to 1\",\n StatusCode.InvalidAction,\n );\n }\n if (maxIntervalCeilingSeconds < minIntervalFloorSeconds) {\n throw new StatusResponseError(\n \"maxIntervalCeilingSeconds should be greater or equal to minIntervalFloorSeconds\",\n StatusCode.InvalidAction,\n );\n }\n\n // TODO: Interpret specs:\n // The publisher SHALL compute an appropriate value for the MaxInterval field in the action. This SHALL respect the following constraint: MinIntervalFloor \u2264 MaxInterval \u2264 MAX(SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT=60mn, MaxIntervalCeiling)\n\n if (this.#nextSubscriptionId === 0xffffffff) this.#nextSubscriptionId = 0;\n const subscriptionId = this.#nextSubscriptionId++;\n const subscriptionHandler = new SubscriptionHandler(\n subscriptionId,\n session,\n this.#endpointStructure,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n this.#eventHandler,\n isFabricFiltered,\n minIntervalFloorSeconds,\n maxIntervalCeilingSeconds,\n () => this.#subscriptionMap.delete(subscriptionId),\n this.#subscriptionConfig,\n );\n\n try {\n // Send initial data report to prime the subscription with initial data\n await subscriptionHandler.sendInitialReport(\n messenger,\n (path, attribute) =>\n this.readAttribute(\n path,\n attribute,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(path.endpointId)!,\n ),\n (path, event, eventFilters) =>\n this.readEvent(\n path,\n eventFilters,\n event,\n exchange,\n isFabricFiltered,\n message,\n this.#endpointStructure.getEndpoint(path.endpointId)!,\n ),\n );\n } catch (error: any) {\n logger.error(\n `Subscription ${subscriptionId} for Session ${session.id}: Error while sending initial data reports`,\n error,\n );\n await subscriptionHandler.cancel(); // Cleanup\n if (error instanceof StatusResponseError) {\n logger.info(`Sending status response ${error.code} for interaction error: ${error.message}`);\n await messenger.sendStatus(error.code);\n }\n await messenger.close();\n return; // Make sure to not bubble up the exception\n }\n\n if (!keepSubscriptions) {\n logger.debug(`Clear subscriptions for Session ${session.name} because keepSubscriptions=false`);\n await session.clearSubscriptions(true);\n }\n\n const maxInterval = subscriptionHandler.getMaxInterval();\n logger.info(\n `Successfully created subscription ${subscriptionId} for Session ${\n session.id\n }. Updates: ${minIntervalFloorSeconds} - ${maxIntervalCeilingSeconds} => ${maxInterval} seconds (sendInterval = ${subscriptionHandler.getSendInterval()} seconds)`,\n );\n // Then send the subscription response\n await messenger.send(\n MessageType.SubscribeResponse,\n TlvSubscribeResponse.encode({\n subscriptionId,\n maxInterval,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n }),\n );\n\n this.#subscriptionMap.set(subscriptionId, subscriptionHandler);\n session.addSubscription(subscriptionHandler);\n subscriptionHandler.activateSendingUpdates();\n }\n\n async handleInvokeRequest(\n exchange: MessageExchange<MatterDevice>,\n { invokeRequests, timedRequest, suppressResponse, interactionModelRevision }: InvokeRequest,\n message: Message,\n ): Promise<InvokeResponse> {\n logger.debug(\n `Received invoke request from ${exchange.channel.name}: ${invokeRequests\n .map(({ commandPath: { endpointId, clusterId, commandId } }) =>\n this.#endpointStructure.resolveCommandName({ endpointId, clusterId, commandId }),\n )\n .join(\", \")}, suppressResponse=${suppressResponse}`,\n );\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n const receivedWithinTimedInteraction = exchange.hasActiveTimedInteraction();\n if (exchange.hasExpiredTimedInteraction()) {\n exchange.clearTimedInteraction(); // ??\n throw new StatusResponseError(`Timed request window expired. Decline invoke request.`, StatusCode.Timeout);\n }\n\n if (timedRequest !== exchange.hasTimedInteraction()) {\n throw new StatusResponseError(\n `timedRequest flag of invoke interaction (${timedRequest}) mismatch with expected timed interaction (${receivedWithinTimedInteraction}).`,\n StatusCode.TimedRequestMismatch,\n );\n }\n\n if (receivedWithinTimedInteraction) {\n logger.debug(`Invoke request from ${exchange.channel.name} received while timed interaction is running.`);\n exchange.clearTimedInteraction();\n if (message.packetHeader.sessionType !== SessionType.Unicast) {\n throw new StatusResponseError(\n \"Invoke requests are only allowed on unicast sessions when a timed interaction is running.\",\n StatusCode.InvalidAction,\n ); // ???\n }\n }\n\n if (invokeRequests.length > 1) {\n throw new StatusResponseError(\"Multi-command invoke requests are not supported\", StatusCode.InvalidAction);\n }\n\n invokeRequests.forEach(({ commandPath }) => validateCommandPath(commandPath));\n\n const invokeResponses: TypeFromSchema<typeof TlvInvokeResponseData>[] = [];\n\n await Promise.all(\n invokeRequests.flatMap(async ({ commandPath, commandFields }) => {\n const commands = this.#endpointStructure.getCommands([commandPath]);\n\n // TODO also check ACL and Timed, Fabric scoping constrains\n\n if (commands.length === 0) {\n // TODO Also check nodeId\n if (!isConcreteCommandPath(commandPath)) {\n // Wildcard path: Just ignore\n logger.debug(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n commandPath,\n )} ignore non-existing attribute`,\n );\n } else {\n const { endpointId, clusterId, commandId } = commandPath;\n invokeResponses.push(\n tryCatch(\n () => {\n this.#endpointStructure.validateConcreteCommandPath(\n endpointId,\n clusterId,\n commandId,\n );\n throw new InternalError(\n \"validateConcreteCommandPath should throw StatusResponseError but did not.\",\n );\n },\n StatusResponseError,\n error => {\n logger.debug(\n `Invoke from ${\n exchange.channel.name\n }: ${this.#endpointStructure.resolveCommandName(\n commandPath,\n )} unsupported path: Status=${error.code}`,\n );\n return { status: { commandPath, status: { status: error.code } } };\n },\n ),\n );\n }\n return;\n }\n\n for (const { command, path } of commands) {\n const { endpointId } = path;\n if (endpointId === undefined) {\n // Should never happen\n logger.error(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n path,\n )} invalid path because empty endpoint!`,\n );\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.UnsupportedEndpoint } },\n });\n continue;\n }\n const endpoint = this.#endpointStructure.getEndpoint(endpointId);\n if (endpoint === undefined) {\n // Should never happen\n logger.error(\n `Invoke from ${exchange.channel.name}: ${this.#endpointStructure.resolveCommandName(\n path,\n )} invalid path because endpoint not found!`,\n );\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.UnsupportedEndpoint } },\n });\n continue;\n }\n if (command.requiresTimedInteraction && !receivedWithinTimedInteraction) {\n logger.debug(`This invoke requires a timed interaction which is not initialized.`);\n invokeResponses.push({\n status: { commandPath: path, status: { status: StatusCode.NeedsTimedInteraction } },\n });\n continue;\n }\n\n const result = await tryCatchAsync(\n async () =>\n await this.invokeCommand(\n path,\n command,\n exchange,\n commandFields ?? TlvNoArguments.encodeTlv(commandFields),\n message,\n endpoint,\n receivedWithinTimedInteraction,\n ),\n StatusResponseError,\n async error => {\n const errorLogText = `Error ${Diagnostic.hex(error.code)}${\n error.clusterCode !== undefined ? `/${Diagnostic.hex(error.clusterCode)}` : \"\"\n } while invoking command: ${error.message}`;\n if (error instanceof ValidationError) {\n logger.info(\n `Validation-${errorLogText}${error.fieldName !== undefined ? ` in field ${error.fieldName}` : \"\"}`,\n );\n } else {\n logger.info(errorLogText);\n }\n return {\n code: error.code,\n clusterCode: error.clusterCode,\n responseId: command.responseId,\n response: TlvNoResponse.encodeTlv(),\n };\n },\n );\n const { code, clusterCode, responseId, response } = result;\n if (response.length === 0) {\n invokeResponses.push({\n status: { commandPath: path, status: { status: code, clusterStatus: clusterCode } },\n });\n } else {\n invokeResponses.push({\n command: {\n commandPath: { ...path, commandId: responseId },\n commandFields: response,\n },\n });\n }\n }\n }),\n );\n\n // TODO support suppressResponse for responses\n return {\n suppressResponse: false,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n invokeResponses,\n };\n }\n\n protected async invokeCommand(\n _path: CommandPath,\n command: CommandServer<any, any>,\n exchange: MessageExchange<MatterDevice>,\n commandFields: any,\n message: Message,\n endpoint: EndpointInterface,\n _receivedWithinTimedInteraction = false,\n ) {\n return command.invoke(exchange.session, commandFields, message, endpoint);\n }\n\n handleTimedRequest(exchange: MessageExchange<MatterDevice>, { timeout, interactionModelRevision }: TimedRequest) {\n logger.debug(`Received timed request (${timeout}ms) from ${exchange.channel.name}`);\n\n if (interactionModelRevision > INTERACTION_MODEL_REVISION) {\n logger.debug(\n `Interaction model revision of sender ${interactionModelRevision} is higher than supported ${INTERACTION_MODEL_REVISION}.`,\n );\n }\n\n exchange.startTimedInteraction(timeout);\n }\n\n async close() {\n this.#isClosing = true;\n for (const subscription of this.#subscriptionMap.values()) {\n await subscription.cancel(true);\n }\n }\n}\n\nexport namespace InteractionServer {\n export interface Configuration {\n readonly subscriptionOptions?: SubscriptionOptions;\n readonly eventHandler: EventHandler;\n readonly endpointStructure: InteractionEndpointStructure;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["eventFilters"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SecureChannelProtocol.d.ts","sourceRoot":"","sources":["../../../../src/protocol/securechannel/SecureChannelProtocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGpE,OAAO,EAAwC,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAYpG,qBAAa,qCAAsC,YAAW,eAAe,CAAC,GAAG,CAAC;IAC9E,KAAK,IAAI,MAAM;IAIT,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAc9D,yBAAyB,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAoC1E,KAAK;CAGd;AAED,qBAAa,qBAAsB,SAAQ,qCAAqC;IAIhE,OAAO,CAAC,8BAA8B;IAHlD,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;gBAEjC,8BAA8B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAIvE,mBAAmB,CAAC,UAAU,EAAE,UAAU;IAI1C,sBAAsB;IAIP,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAgC7E,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAGjE"}
1
+ {"version":3,"file":"SecureChannelProtocol.d.ts","sourceRoot":"","sources":["../../../../src/protocol/securechannel/SecureChannelProtocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGpE,OAAO,EAAwC,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAapG,qBAAa,qCAAsC,YAAW,eAAe,CAAC,GAAG,CAAC;IAC9E,KAAK,IAAI,MAAM;IAIT,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAe9D,yBAAyB,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAoC1E,KAAK;CAGd;AAED,qBAAa,qBAAsB,SAAQ,qCAAqC;IAIhE,OAAO,CAAC,8BAA8B;IAHlD,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;gBAEjC,8BAA8B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAIvE,mBAAmB,CAAC,UAAU,EAAE,UAAU;IAI1C,sBAAsB;IAIP,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO;IAgC7E,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAGjE"}
@@ -8,6 +8,7 @@ import { Logger } from "../../log/Logger.js";
8
8
  import { assertSecureSession } from "../../session/SecureSession.js";
9
9
  import { CaseServer } from "../../session/case/CaseServer.js";
10
10
  import { MaximumPasePairingErrorsReachedError } from "../../session/pase/PaseServer.js";
11
+ import { StatusCode, StatusResponseError } from "../interaction/StatusCode.js";
11
12
  import {
12
13
  GeneralStatusCode,
13
14
  MessageType,
@@ -28,8 +29,9 @@ class StatusReportOnlySecureChannelProtocol {
28
29
  await this.handleInitialStatusReport(exchange, message);
29
30
  break;
30
31
  default:
31
- throw new MatterFlowError(
32
- `Unexpected initial message on secure channel protocol: ${messageType.toString(16)}`
32
+ throw new StatusResponseError(
33
+ `Unexpected initial message on secure channel protocol: ${messageType.toString(16)}`,
34
+ StatusCode.InvalidAction
33
35
  );
34
36
  }
35
37
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/protocol/securechannel/SecureChannelProtocol.ts"],
4
- "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Message } from \"../../codec/MessageCodec.js\";\nimport { MatterFlowError } from \"../../common/MatterError.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { MessageExchange } from \"../../protocol/MessageExchange.js\";\nimport { ProtocolHandler } from \"../../protocol/ProtocolHandler.js\";\nimport { assertSecureSession } from \"../../session/SecureSession.js\";\nimport { CaseServer } from \"../../session/case/CaseServer.js\";\nimport { MaximumPasePairingErrorsReachedError, PaseServer } from \"../../session/pase/PaseServer.js\";\nimport {\n GeneralStatusCode,\n MessageType,\n ProtocolStatusCode,\n SECURE_CHANNEL_PROTOCOL_ID,\n} from \"./SecureChannelMessages.js\";\nimport { ChannelStatusResponseError, SecureChannelMessenger } from \"./SecureChannelMessenger.js\";\nimport { TlvSecureChannelStatusMessage } from \"./SecureChannelStatusMessageSchema.js\";\n\nconst logger = Logger.get(\"SecureChannelProtocol\");\n\nexport class StatusReportOnlySecureChannelProtocol implements ProtocolHandler<any> {\n getId(): number {\n return SECURE_CHANNEL_PROTOCOL_ID;\n }\n\n async onNewExchange(exchange: MessageExchange<any>, message: Message) {\n const messageType = message.payloadHeader.messageType;\n\n switch (messageType) {\n case MessageType.StatusReport:\n await this.handleInitialStatusReport(exchange, message);\n break;\n default:\n throw new MatterFlowError(\n `Unexpected initial message on secure channel protocol: ${messageType.toString(16)}`,\n );\n }\n }\n\n async handleInitialStatusReport(exchange: MessageExchange<any>, message: Message) {\n const {\n payloadHeader: { messageType },\n payload,\n } = message;\n if (messageType !== MessageType.StatusReport) {\n throw new MatterFlowError(\n `Unexpected message type on secure channel protocol, expected StatusReport: ${messageType.toString(\n 16,\n )}`,\n );\n }\n\n const { generalStatus, protocolId, protocolStatus } = TlvSecureChannelStatusMessage.decode(payload);\n if (generalStatus !== GeneralStatusCode.Success) {\n throw new ChannelStatusResponseError(\n `Received general error status (${protocolId})`,\n generalStatus,\n protocolStatus,\n );\n }\n if (protocolStatus !== ProtocolStatusCode.CloseSession) {\n throw new ChannelStatusResponseError(\n `Received general success status, but protocol status is not CloseSession`,\n generalStatus,\n protocolStatus,\n );\n }\n\n const { session } = exchange;\n assertSecureSession(session);\n logger.debug(`Peer requested to close session ${session.name}. Remove session now.`);\n // TODO: and do more - see Core Specs 5.5\n await session.destroy(false, false);\n }\n\n async close() {\n // Nothing to do\n }\n}\n\nexport class SecureChannelProtocol extends StatusReportOnlySecureChannelProtocol {\n private paseCommissioner: PaseServer | undefined;\n private readonly caseCommissioner = new CaseServer();\n\n constructor(private commissioningCancelledCallback: () => Promise<void>) {\n super();\n }\n\n setPaseCommissioner(paseServer: PaseServer) {\n this.paseCommissioner = paseServer;\n }\n\n removePaseCommissioner() {\n this.paseCommissioner = undefined;\n }\n\n override async onNewExchange(exchange: MessageExchange<any>, message: Message) {\n const messageType = message.payloadHeader.messageType;\n\n switch (messageType) {\n case MessageType.PbkdfParamRequest:\n if (this.paseCommissioner === undefined) {\n // Cleaner to return an error (ok for chip-tool as it seems)?\n // Formally we should not respond at all which leads to retries and such\n const messenger = new SecureChannelMessenger(exchange);\n await messenger.sendError(ProtocolStatusCode.InvalidParam);\n await messenger.close(); // also closes exchange\n return;\n }\n try {\n await this.paseCommissioner.onNewExchange(exchange);\n } catch (error) {\n if (error instanceof MaximumPasePairingErrorsReachedError) {\n logger.info(\"Maximum number of PASE pairing errors reached, cancelling commissioning.\");\n await this.commissioningCancelledCallback();\n } else {\n throw error;\n }\n }\n break;\n case MessageType.Sigma1:\n await this.caseCommissioner.onNewExchange(exchange);\n break;\n default:\n await super.onNewExchange(exchange, message);\n }\n }\n\n static isStandaloneAck(protocolId: number, messageType: number) {\n return protocolId === SECURE_CHANNEL_PROTOCOL_ID && messageType === MessageType.StandaloneAck;\n }\n}\n"],
5
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,uBAAuB;AAChC,SAAS,cAAc;AAGvB,SAAS,2BAA2B;AACpC,SAAS,kBAAkB;AAC3B,SAAS,4CAAwD;AACjE;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,4BAA4B,8BAA8B;AACnE,SAAS,qCAAqC;AAE9C,MAAM,SAAS,OAAO,IAAI,uBAAuB;AAE1C,MAAM,sCAAsE;AAAA,EAC/E,QAAgB;AACZ,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,cAAc,UAAgC,SAAkB;AAClE,UAAM,cAAc,QAAQ,cAAc;AAE1C,YAAQ,aAAa;AAAA,MACjB,KAAK,YAAY;AACb,cAAM,KAAK,0BAA0B,UAAU,OAAO;AACtD;AAAA,MACJ;AACI,cAAM,IAAI;AAAA,UACN,0DAA0D,YAAY,SAAS,EAAE,CAAC;AAAA,QACtF;AAAA,IACR;AAAA,EACJ;AAAA,EAEA,MAAM,0BAA0B,UAAgC,SAAkB;AAC9E,UAAM;AAAA,MACF,eAAe,EAAE,YAAY;AAAA,MAC7B;AAAA,IACJ,IAAI;AACJ,QAAI,gBAAgB,YAAY,cAAc;AAC1C,YAAM,IAAI;AAAA,QACN,8EAA8E,YAAY;AAAA,UACtF;AAAA,QACJ,CAAC;AAAA,MACL;AAAA,IACJ;AAEA,UAAM,EAAE,eAAe,YAAY,eAAe,IAAI,8BAA8B,OAAO,OAAO;AAClG,QAAI,kBAAkB,kBAAkB,SAAS;AAC7C,YAAM,IAAI;AAAA,QACN,kCAAkC,UAAU;AAAA,QAC5C;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AACA,QAAI,mBAAmB,mBAAmB,cAAc;AACpD,YAAM,IAAI;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,EAAE,QAAQ,IAAI;AACpB,wBAAoB,OAAO;AAC3B,WAAO,MAAM,mCAAmC,QAAQ,IAAI,uBAAuB;AAEnF,UAAM,QAAQ,QAAQ,OAAO,KAAK;AAAA,EACtC;AAAA,EAEA,MAAM,QAAQ;AAAA,EAEd;AACJ;AAEO,MAAM,8BAA8B,sCAAsC;AAAA,EAI7E,YAAoB,gCAAqD;AACrE,UAAM;AADU;AAFpB,SAAiB,mBAAmB,IAAI,WAAW;AAAA,EAInD;AAAA,EAEA,oBAAoB,YAAwB;AACxC,SAAK,mBAAmB;AAAA,EAC5B;AAAA,EAEA,yBAAyB;AACrB,SAAK,mBAAmB;AAAA,EAC5B;AAAA,EAEA,MAAe,cAAc,UAAgC,SAAkB;AAC3E,UAAM,cAAc,QAAQ,cAAc;AAE1C,YAAQ,aAAa;AAAA,MACjB,KAAK,YAAY;AACb,YAAI,KAAK,qBAAqB,QAAW;AAGrC,gBAAM,YAAY,IAAI,uBAAuB,QAAQ;AACrD,gBAAM,UAAU,UAAU,mBAAmB,YAAY;AACzD,gBAAM,UAAU,MAAM;AACtB;AAAA,QACJ;AACA,YAAI;AACA,gBAAM,KAAK,iBAAiB,cAAc,QAAQ;AAAA,QACtD,SAAS,OAAO;AACZ,cAAI,iBAAiB,sCAAsC;AACvD,mBAAO,KAAK,0EAA0E;AACtF,kBAAM,KAAK,+BAA+B;AAAA,UAC9C,OAAO;AACH,kBAAM;AAAA,UACV;AAAA,QACJ;AACA;AAAA,MACJ,KAAK,YAAY;AACb,cAAM,KAAK,iBAAiB,cAAc,QAAQ;AAClD;AAAA,MACJ;AACI,cAAM,MAAM,cAAc,UAAU,OAAO;AAAA,IACnD;AAAA,EACJ;AAAA,EAEA,OAAO,gBAAgB,YAAoB,aAAqB;AAC5D,WAAO,eAAe,8BAA8B,gBAAgB,YAAY;AAAA,EACpF;AACJ;",
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Message } from \"../../codec/MessageCodec.js\";\nimport { MatterFlowError } from \"../../common/MatterError.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { MessageExchange } from \"../../protocol/MessageExchange.js\";\nimport { ProtocolHandler } from \"../../protocol/ProtocolHandler.js\";\nimport { assertSecureSession } from \"../../session/SecureSession.js\";\nimport { CaseServer } from \"../../session/case/CaseServer.js\";\nimport { MaximumPasePairingErrorsReachedError, PaseServer } from \"../../session/pase/PaseServer.js\";\nimport { StatusCode, StatusResponseError } from \"../interaction/StatusCode.js\";\nimport {\n GeneralStatusCode,\n MessageType,\n ProtocolStatusCode,\n SECURE_CHANNEL_PROTOCOL_ID,\n} from \"./SecureChannelMessages.js\";\nimport { ChannelStatusResponseError, SecureChannelMessenger } from \"./SecureChannelMessenger.js\";\nimport { TlvSecureChannelStatusMessage } from \"./SecureChannelStatusMessageSchema.js\";\n\nconst logger = Logger.get(\"SecureChannelProtocol\");\n\nexport class StatusReportOnlySecureChannelProtocol implements ProtocolHandler<any> {\n getId(): number {\n return SECURE_CHANNEL_PROTOCOL_ID;\n }\n\n async onNewExchange(exchange: MessageExchange<any>, message: Message) {\n const messageType = message.payloadHeader.messageType;\n\n switch (messageType) {\n case MessageType.StatusReport:\n await this.handleInitialStatusReport(exchange, message);\n break;\n default:\n throw new StatusResponseError(\n `Unexpected initial message on secure channel protocol: ${messageType.toString(16)}`,\n StatusCode.InvalidAction,\n );\n }\n }\n\n async handleInitialStatusReport(exchange: MessageExchange<any>, message: Message) {\n const {\n payloadHeader: { messageType },\n payload,\n } = message;\n if (messageType !== MessageType.StatusReport) {\n throw new MatterFlowError(\n `Unexpected message type on secure channel protocol, expected StatusReport: ${messageType.toString(\n 16,\n )}`,\n );\n }\n\n const { generalStatus, protocolId, protocolStatus } = TlvSecureChannelStatusMessage.decode(payload);\n if (generalStatus !== GeneralStatusCode.Success) {\n throw new ChannelStatusResponseError(\n `Received general error status (${protocolId})`,\n generalStatus,\n protocolStatus,\n );\n }\n if (protocolStatus !== ProtocolStatusCode.CloseSession) {\n throw new ChannelStatusResponseError(\n `Received general success status, but protocol status is not CloseSession`,\n generalStatus,\n protocolStatus,\n );\n }\n\n const { session } = exchange;\n assertSecureSession(session);\n logger.debug(`Peer requested to close session ${session.name}. Remove session now.`);\n // TODO: and do more - see Core Specs 5.5\n await session.destroy(false, false);\n }\n\n async close() {\n // Nothing to do\n }\n}\n\nexport class SecureChannelProtocol extends StatusReportOnlySecureChannelProtocol {\n private paseCommissioner: PaseServer | undefined;\n private readonly caseCommissioner = new CaseServer();\n\n constructor(private commissioningCancelledCallback: () => Promise<void>) {\n super();\n }\n\n setPaseCommissioner(paseServer: PaseServer) {\n this.paseCommissioner = paseServer;\n }\n\n removePaseCommissioner() {\n this.paseCommissioner = undefined;\n }\n\n override async onNewExchange(exchange: MessageExchange<any>, message: Message) {\n const messageType = message.payloadHeader.messageType;\n\n switch (messageType) {\n case MessageType.PbkdfParamRequest:\n if (this.paseCommissioner === undefined) {\n // Cleaner to return an error (ok for chip-tool as it seems)?\n // Formally we should not respond at all which leads to retries and such\n const messenger = new SecureChannelMessenger(exchange);\n await messenger.sendError(ProtocolStatusCode.InvalidParam);\n await messenger.close(); // also closes exchange\n return;\n }\n try {\n await this.paseCommissioner.onNewExchange(exchange);\n } catch (error) {\n if (error instanceof MaximumPasePairingErrorsReachedError) {\n logger.info(\"Maximum number of PASE pairing errors reached, cancelling commissioning.\");\n await this.commissioningCancelledCallback();\n } else {\n throw error;\n }\n }\n break;\n case MessageType.Sigma1:\n await this.caseCommissioner.onNewExchange(exchange);\n break;\n default:\n await super.onNewExchange(exchange, message);\n }\n }\n\n static isStandaloneAck(protocolId: number, messageType: number) {\n return protocolId === SECURE_CHANNEL_PROTOCOL_ID && messageType === MessageType.StandaloneAck;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-chip/matter.js",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Matter protocol in pure js",
5
5
  "keywords": [
6
6
  "iot",
@@ -36,7 +36,7 @@
36
36
  "@noble/curves": "^1.4.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@project-chip/matter.js-tools": "0.9.1",
39
+ "@project-chip/matter.js-tools": "0.9.2",
40
40
  "@types/chai": "^4.3.12",
41
41
  "@types/mocha": "^10.0.6",
42
42
  "@types/wtfnode": "^0.7.3",
@@ -169,5 +169,5 @@
169
169
  "publishConfig": {
170
170
  "access": "public"
171
171
  },
172
- "gitHead": "49679bb96cddf408fa26f0e8dcf3a8f2f1eda5f5"
172
+ "gitHead": "d638f16736899f69cc752581454960c9dc1904d2"
173
173
  }
@@ -10,6 +10,8 @@ import { AttributeElement, Globals } from "../elements/index.js";
10
10
  import { Model } from "./Model.js";
11
11
  import { PropertyModel } from "./PropertyModel.js";
12
12
 
13
+ // Full set of global IDs per core spec 1.3
14
+ export const GLOBAL_IDS = new Set([0xfffd, 0xfffc, 0xfffb, 0xfffa, 0xfff9, 0xfff8]);
13
15
  const globalIds = new Set<number>();
14
16
  for (const element of Object.values(Globals)) {
15
17
  if (element.tag === ElementTag.Attribute) {
@@ -11,6 +11,7 @@ import { ActionTracer } from "../../behavior/context/ActionTracer.js";
11
11
  import { NodeActivity } from "../../behavior/context/NodeActivity.js";
12
12
  import { OnlineContext } from "../../behavior/context/server/OnlineContext.js";
13
13
  import { AccessControlServer } from "../../behavior/definitions/access-control/AccessControlServer.js";
14
+ import { AccessControlCluster } from "../../cluster/definitions/AccessControlCluster.js";
14
15
  import { AnyAttributeServer, AttributeServer } from "../../cluster/server/AttributeServer.js";
15
16
  import { CommandServer } from "../../cluster/server/CommandServer.js";
16
17
  import { EventServer } from "../../cluster/server/EventServer.js";
@@ -48,6 +49,9 @@ interface WithActivity {
48
49
  [activityKey]?: NodeActivity.Activity;
49
50
  }
50
51
 
52
+ const AclClusterId = AccessControlCluster.id;
53
+ const AclAttributeId = AccessControlCluster.attributes.acl.id;
54
+
51
55
  /**
52
56
  * Wire up an InteractionServer that initializes an InvocationContext earlier than the cluster API supports.
53
57
  *
@@ -67,6 +71,7 @@ export class TransactionalInteractionServer extends InteractionServer {
67
71
  #activity: NodeActivity;
68
72
  #newActivityBlocked = false;
69
73
  #aclServer?: AccessControlServer;
74
+ #aclUpdateIsDelayed = false;
70
75
 
71
76
  constructor(endpoint: Endpoint<ServerNode.RootEndpoint>) {
72
77
  const structure = new InteractionEndpointStructure();
@@ -193,13 +198,13 @@ export class TransactionalInteractionServer extends InteractionServer {
193
198
  writeRequest: WriteRequest,
194
199
  message: Message,
195
200
  ): Promise<WriteResponse> {
196
- // TODO: This is a hack to prevent the ACL from updating while we are in the middle of a write transaction and will
197
- // be removed again once we somehow handle relevant sub transactions
198
- this.aclServer.aclUpdateDelayed = true;
199
-
200
201
  const result = await super.handleWriteRequest(exchange, writeRequest, message);
201
202
 
202
- this.aclServer.aclUpdateDelayed = false;
203
+ // We delayed the ACL update during the write transaction, so we need to update it now that anything is written
204
+ if (this.#aclUpdateIsDelayed) {
205
+ this.aclServer.aclUpdateDelayed = false;
206
+ this.#aclUpdateIsDelayed = false;
207
+ }
203
208
  return result;
204
209
  }
205
210
 
@@ -216,7 +221,17 @@ export class TransactionalInteractionServer extends InteractionServer {
216
221
  const writeAttribute = () =>
217
222
  super.writeAttribute(path, attribute, value, exchange, message, endpoint, timed, isListWrite);
218
223
 
219
- // TODO add handling for List writes that require sub transactions and remove the delayed ACL update
224
+ if (path.endpointId === 0 && path.clusterId === AclClusterId && path.attributeId === AclAttributeId) {
225
+ // This is a hack to prevent the ACL from updating while we are in the middle of a write transaction
226
+ // and is needed because Acl should not become effective during writing of the ACL itself.
227
+ this.aclServer.aclUpdateDelayed = true;
228
+ this.#aclUpdateIsDelayed = true;
229
+ } else if (this.#aclUpdateIsDelayed) {
230
+ // Ok it seems that acl was written, but we now write another path, so we can update Acl attribute now
231
+ this.aclServer.aclUpdateDelayed = false;
232
+ this.#aclUpdateIsDelayed = false;
233
+ }
234
+
220
235
  return OnlineContext({
221
236
  activity: (exchange as WithActivity)[activityKey],
222
237
  timed,
@@ -36,7 +36,7 @@ export class ChannelManager {
36
36
  #findLeastActiveChannel(channels: MessageChannel<any>[]) {
37
37
  let oldest = channels[0];
38
38
  for (const channel of channels) {
39
- if (channel.session.activeTimestamp < oldest.session.activeTimestamp) {
39
+ if (channel.session.timestamp < oldest.session.timestamp) {
40
40
  oldest = channel;
41
41
  }
42
42
  }