From 9dd9639dd7c7dfb4712d389c4bcd14de9fa74840 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 23 May 2023 20:36:37 +0300 Subject: [PATCH] Add spec for MSC2659: application service ping endpoint (#1516) --- .../newsfragments/1516.feature | 1 + .../newsfragments/1516.new | 1 + content/application-service-api.md | 57 +++++++ data/api/application-service/ping.yaml | 63 ++++++++ data/api/client-server/appservice_ping.yaml | 150 ++++++++++++++++++ 5 files changed, 272 insertions(+) create mode 100644 changelogs/application_service/newsfragments/1516.feature create mode 100644 changelogs/application_service/newsfragments/1516.new create mode 100644 data/api/application-service/ping.yaml create mode 100644 data/api/client-server/appservice_ping.yaml diff --git a/changelogs/application_service/newsfragments/1516.feature b/changelogs/application_service/newsfragments/1516.feature new file mode 100644 index 00000000..ee222fb0 --- /dev/null +++ b/changelogs/application_service/newsfragments/1516.feature @@ -0,0 +1 @@ +Add homeserver->appservice ping mechanism, as per [MSC2659](https://github.com/matrix-org/matrix-spec-proposals/pull/2659). Contributed by @tulir at @beeper. diff --git a/changelogs/application_service/newsfragments/1516.new b/changelogs/application_service/newsfragments/1516.new new file mode 100644 index 00000000..c6244075 --- /dev/null +++ b/changelogs/application_service/newsfragments/1516.new @@ -0,0 +1 @@ +Add `POST /_matrix/app/v1/ping` and `POST /_matrix/client/v1/appservice/{appserviceId}/ping` endpoints as per [MSC2659](https://github.com/matrix-org/matrix-spec-proposals/pull/2659). diff --git a/content/application-service-api.md b/content/application-service-api.md index 7a14869a..f3db06cf 100644 --- a/content/application-service-api.md +++ b/content/application-service-api.md @@ -207,6 +207,54 @@ processed the events. {{% http-api spec="application-service" api="transactions" %}} +#### Pinging + +{{% added-in v="1.7" %}} + +The application service API includes a ping mechanism to allow +appservices to ensure that the homeserver can reach the appservice. +Appservices may use this mechanism to detect misconfigurations and +report them appropriately. + +Implementations using this mechanism should take care to not fail +entirely in the event of temporary issues, e.g. gracefully handling +cases where the appservice is started before the homeserver. + +The mechanism works as follows (note: the human-readable `error` fields +have been omitted for brevity): + +**Typical** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} + HS <--- AS : 200 OK {} +AS <--- HS : 200 OK {"duration_ms": 123} +``` + +**Incorrect `hs_token`** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} + HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"} +AS <--- HS : 502 Bad Gateway {"errcode": "M_BAD_STATUS", "status": 403, "body": "{\"errcode\": \"M_FORBIDDEN\"}"} +``` + +**Can't connect to appservice** + +``` +AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"} + HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"} +AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"} +``` + +The `/_matrix/app/v1/ping` endpoint is described here. The +[`/_matrix/client/v1/appservice/{appserviceId}/ping`](#post_matrixclientv1appserviceappserviceidping) +endpoint is under the Client-Server API extensions section below. + +{{% http-api spec="application-service" api="ping" %}} + #### Querying The application service API includes two querying APIs: for room aliases @@ -388,6 +436,15 @@ an application service-defined namespace will receive the same `M_EXCLUSIVE` error code, but only if the application service has defined the namespace as `exclusive`. +#### Pinging + +{{% added-in v="1.7" %}} + +This is the client-server API companion endpoint for the +[pinging](#pinging) mechanism described above. + +{{% http-api spec="client-server" api="appservice_ping" %}} + #### Using `/sync` and `/events` Application services wishing to use `/sync` or `/events` from the diff --git a/data/api/application-service/ping.yaml b/data/api/application-service/ping.yaml new file mode 100644 index 00000000..18682f11 --- /dev/null +++ b/data/api/application-service/ping.yaml @@ -0,0 +1,63 @@ +# Copyright 2023 Tulir Asokan +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Application Service API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/app/v1 +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/ping": + post: + x-addedInMatrixVersion: "1.7" + summary: Ping the application service + description: |- + This API is called by the homeserver to ensure that the connection works + and the `hs_token` the homeserver has is correct. + + Currently this is only called by the homeserver as a direct result of + the application service calling + [`POST /_matrix/client/v1/appservice/{appserviceId}/ping`](#post_matrixclientv1appserviceappserviceidping). + operationId: ping + security: + - homeserverAccessToken: [] + parameters: + - in: body + name: body + description: Ping body with optional transaction ID. + schema: + type: object + example: { + "transaction_id": "mautrix-go_1683636478256400935_123" + } + properties: + transaction_id: + type: string + description: |- + A transaction ID for the ping, copied directly from the + `POST /_matrix/client/v1/appservice/{appserviceId}/ping` call. + responses: + 200: + description: The provided `hs_token` is valid and the ping request was successful. + examples: + application/json: {} + schema: + type: object diff --git a/data/api/client-server/appservice_ping.yaml b/data/api/client-server/appservice_ping.yaml new file mode 100644 index 00000000..4075e901 --- /dev/null +++ b/data/api/client-server/appservice_ping.yaml @@ -0,0 +1,150 @@ +# Copyright 2023 Tulir Asokan +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Client-Server Application Service Ping API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + # Note: this is the same access_token definition used elsewhere in the client + # server API, however this expects an access token for an application service. + $ref: definitions/security.yaml +paths: + "/appservice/{appserviceId}/ping": + post: + x-addedInMatrixVersion: "1.7" + summary: |- + Ask the homeserver to ping the application service to ensure the connection works. + description: |- + This API asks the homeserver to call the + [`/_matrix/app/v1/ping`](#post_matrixappv1ping) endpoint on the + application service to ensure that the homeserver can communicate + with the application service. + + This API requires the use of an application service access token (`as_token`) + instead of a typical client's access token. This API cannot be invoked by + users who are not identified as application services. Additionally, the + appservice ID in the path must be the same as the appservice whose `as_token` + is being used. + operationId: pingAppservice + parameters: + - in: path + type: string + name: appserviceId + description: |- + The appservice ID of the appservice to ping. This must be the same + as the appservice whose `as_token` is being used to authenticate the + request. + required: true + x-example: "telegram" + - in: body + name: body + required: true + schema: + type: object + properties: + transaction_id: + type: string + description: |- + An optional transaction ID that is passed through to the `/_matrix/app/v1/ping` call. + example: "mautrix-go_1683636478256400935_123" + security: + # again, this is the appservice's token - not a typical client's + - accessToken: [] + responses: + 200: + description: The ping was successful. + schema: + type: object + properties: + duration_ms: + type: integer + description: |- + The duration in milliseconds that the + [`/_matrix/app/v1/ping`](#post_matrixappv1ping) + request took from the homeserver's point of view. + examples: + application/json: {"duration_ms": 123} + 400: + description: The application service doesn't have a URL configured. The errcode is `M_URL_NOT_SET`. + schema: + $ref: "definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_URL_NOT_SET", + "error": "Application service doesn't have a URL configured" + } + 403: + description: The access token used to authenticate the request doesn't belong to an appservice, or belongs to a different appservice than the one in the path. The errcode is `M_FORBIDDEN`. + schema: + $ref: "definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_FORBIDDEN", + "error": "Provided access token is not the appservice's as_token" + } + 502: + description: |- + The application service returned a bad status, or the connection failed. + The errcode is `M_BAD_STATUS` or `M_CONNECTION_FAILED`. + + For bad statuses, the response may include `status` and `body` + fields containing the HTTP status code and response body text + respectively to aid with debugging. + schema: + type: object + title: Error + description: A Matrix-level Error + properties: + errcode: + type: string + description: An error code. + enum: [M_BAD_STATUS, M_CONNECTION_FAILED] + error: + type: string + description: A human-readable error message. + example: Ping returned status 401 + status: + type: integer + description: The HTTP status code returned by the appservice. + example: 401 + body: + type: string + description: The HTTP response body returned by the appservice. + example: "{\"errcode\": \"M_UNKNOWN_TOKEN\"}" + required: ["errcode"] + examples: + application/json: { + "errcode": "M_BAD_STATUS", + "error": "Ping returned status 401", + "status": 401, + "body": "{\"errcode\": \"M_UNKNOWN_TOKEN\"}" + } + 504: + description: The connection to the application service timed out. The errcode is `M_CONNECTION_TIMEOUT`. + schema: + $ref: "definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_CONNECTION_TIMEOUT", + "error": "Connection to application service timed out" + }