diff --git a/api/widgets/definitions/api_error.yaml b/api/widgets/definitions/api_error.yaml new file mode 100644 index 00000000000..239632847f9 --- /dev/null +++ b/api/widgets/definitions/api_error.yaml @@ -0,0 +1,41 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: WidgetApiErrorResponse +description: |- + Schema definition for an error response in the Widget API. This is a regular ``WidgetApiResponse`` + object with the ``response`` specified as follows. +allOf: + - $ref: "./api_response.yaml" +properties: + response: + type: object + title: WidgetErrorResponseData + description: |- + The response data. + properties: + error: + type: object + title: WidgetApiError + description: |- + Information about the error that happened. + properties: + message: + type: string + description: |- + Human-readable string for the cause of the error. + example: "Failed to process request: Server returned 500 error" + required: ['message'] + required: ['error'] diff --git a/api/widgets/definitions/api_request.yaml b/api/widgets/definitions/api_request.yaml new file mode 100644 index 00000000000..c8eb7ee260d --- /dev/null +++ b/api/widgets/definitions/api_request.yaml @@ -0,0 +1,55 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: WidgetApiRequest +description: |- + Schema definition for a widget request object over the Widget API. +properties: + api: + type: string + enum: [fromWidget, toWidget] + description: |- + The API for which the request is to be sent over. + example: "fromWidget" + requestId: + type: string + description: |- + An opaque string which uniquely identifies the request in the context of the session. + example: "generated-id-1234" + action: + type: string + description: |- + The action to send to the other party. Custom actions can be sent using the Java package + naming convention as a namespace. + example: "com.example.say_hello" + widgetId: + type: string + description: |- + The widget's ID. + example: "20200827_WidgetExample" + data: + type: object + description: |- + The request data. + additionalProperties: true + example: { + "request-param": "value" + } +required: + - api + - requestId + - action + - widgetId + - data diff --git a/api/widgets/definitions/api_response.yaml b/api/widgets/definitions/api_response.yaml new file mode 100644 index 00000000000..76c9f5442d7 --- /dev/null +++ b/api/widgets/definitions/api_response.yaml @@ -0,0 +1,51 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: WidgetApiResponse +description: |- + Schema definition for a widget response object over the Widget API. + + .. Note:: + This is intentionally designed to allow API users to copy the request object + verbatim and simply append their ``response``. + +allOf: + - $ref: "./api_request.yaml" +properties: + response: + type: object + description: |- + The response data. + additionalProperties: true + example: { + "response-param": "value" + } + # We define other properties from the api_request.yaml schema to override their descriptions + # for context purposes + api: + type: string + enum: [fromWidget, toWidget] + description: The API the request was sent over. + example: "fromWidget" + requestId: + type: string + description: The request ID supplied in the original request. + example: "generated-id-1234" + action: + type: string + description: The action which was invoked. + example: "com.example.say_hello" +required: + - response diff --git a/api/widgets/definitions/capabilities_action.yaml b/api/widgets/definitions/capabilities_action.yaml new file mode 100644 index 00000000000..c0250095a12 --- /dev/null +++ b/api/widgets/definitions/capabilities_action.yaml @@ -0,0 +1,32 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: CapabilitiesActionBase +properties: + api: + type: string + enum: ["toWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "toWidget" + action: + type: string + enum: ["capabilities"] + description: "" # The enum will result in this being "Must be $0" + example: "capabilities" + data: + type: object + description: |- + An empty data object (no request parameters). + example: {} diff --git a/api/widgets/definitions/capabilities_action_request.yaml b/api/widgets/definitions/capabilities_action_request.yaml new file mode 100644 index 00000000000..af749ab42b4 --- /dev/null +++ b/api/widgets/definitions/capabilities_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: CapabilitiesActionRequest +description: |- + Schema definition for a ``toWidget`` API request with action of ``capabilities``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./capabilities_action.yaml" +properties: {} diff --git a/api/widgets/definitions/capabilities_action_response.yaml b/api/widgets/definitions/capabilities_action_response.yaml new file mode 100644 index 00000000000..2f242b2e499 --- /dev/null +++ b/api/widgets/definitions/capabilities_action_response.yaml @@ -0,0 +1,37 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: CapabilitiesActionResponse +description: |- + Schema definition for a response to a ``CapabilitiesActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./capabilities_action_request.yaml" +properties: + response: + type: object + description: |- + The response data. + title: CapabilitiesActionResponseData + properties: + capabilities: + type: array + items: + type: string + description: |- + The list of requested capabilities. An empty array indicates that no capabilities are + requested. + example: ["m.capabilitity.screenshot", "m.sticker"] + required: ['capabilities'] diff --git a/api/widgets/definitions/content_loaded_action.yaml b/api/widgets/definitions/content_loaded_action.yaml new file mode 100644 index 00000000000..4b19076185c --- /dev/null +++ b/api/widgets/definitions/content_loaded_action.yaml @@ -0,0 +1,32 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ContentLoadedActionBase +properties: + api: + type: string + enum: ["fromWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "fromWidget" + action: + type: string + enum: ["content_loaded"] + description: "" # The enum will result in this being "Must be $0" + example: "content_loaded" + data: + type: object + description: |- + An empty data object (no request parameters). + example: {} diff --git a/api/widgets/definitions/content_loaded_action_request.yaml b/api/widgets/definitions/content_loaded_action_request.yaml new file mode 100644 index 00000000000..27552184486 --- /dev/null +++ b/api/widgets/definitions/content_loaded_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ContentLoadedActionRequest +description: |- + Schema definition for a ``fromWidget`` API request with action of ``content_loaded``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./content_loaded_action.yaml" +properties: {} diff --git a/api/widgets/definitions/content_loaded_action_response.yaml b/api/widgets/definitions/content_loaded_action_response.yaml new file mode 100644 index 00000000000..3d8c1eae870 --- /dev/null +++ b/api/widgets/definitions/content_loaded_action_response.yaml @@ -0,0 +1,27 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ContentLoadedActionResponse +description: |- + Schema definition for a response to a ``ContentLoadedActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./content_loaded_action_request.yaml" +properties: + response: + type: object + description: |- + An empty response body to acknowledge the request. + example: {} diff --git a/api/widgets/definitions/custom_data.yaml b/api/widgets/definitions/custom_data.yaml new file mode 100644 index 00000000000..32a0c175425 --- /dev/null +++ b/api/widgets/definitions/custom_data.yaml @@ -0,0 +1,31 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: CustomWidgetData +description: |- + Definition for a widget's ``data`` when using a ``type`` of ``m.custom`` or using an + unknown/unsupported ``type``. Currently no requirements are specified. +properties: + url: + type: string + description: |- + The URL for the embedded content. Required only if the widget's URL does not match + the embedded content, before templating ocurrs. + + Clients should note that not all widgets which get interpretted as custom widgets + will have this property, though all widgets are required to have a higher level ``url`` + which can be used to display them. As such, requirements for this field being present + SHOULD only be enforced upon widgets with an explicit ``type`` of ``m.custom``. + example: "https://matrix.org" diff --git a/api/widgets/definitions/get_openid_action.yaml b/api/widgets/definitions/get_openid_action.yaml new file mode 100644 index 00000000000..0ae60585e04 --- /dev/null +++ b/api/widgets/definitions/get_openid_action.yaml @@ -0,0 +1,33 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: GetOpenIDCredentialsActionBase +properties: + api: + type: string + enum: ["fromWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "fromWidget" + action: + type: string + enum: ["get_openid"] + description: "" # The enum will result in this being "Must be $0" + example: "get_openid" + data: + type: object + title: GetOpenIDCredentialsRequestData + description: |- + An empty request body. + example: {} diff --git a/api/widgets/definitions/get_openid_action_request.yaml b/api/widgets/definitions/get_openid_action_request.yaml new file mode 100644 index 00000000000..bb2a6b6eb82 --- /dev/null +++ b/api/widgets/definitions/get_openid_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: GetOpenIDCredentialsActionRequest +description: |- + Schema definition for a ``fromWidget`` API request with action of ``get_openid``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./get_openid_action.yaml" +properties: {} diff --git a/api/widgets/definitions/get_openid_action_response.yaml b/api/widgets/definitions/get_openid_action_response.yaml new file mode 100644 index 00000000000..d7d8c10c040 --- /dev/null +++ b/api/widgets/definitions/get_openid_action_response.yaml @@ -0,0 +1,44 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: GetOpenIDCredentialsActionResponse +description: |- + Schema definition for a response to a ``GetOpenIDCredentialsActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./get_openid_action_request.yaml" +properties: + response: + type: object + title: GetOpenIDCredentialsActionResponseData + description: |- + The state of the OpenID Connect credentials request with potentially token + information. + + When ``state`` is ``allowed``, several properties (defined below) are required. + They hold the same meaning and specification as their same-named properties in + the response of the Client-Server API ``/user/{userId}/openid/request_token`` + endpoint. + allOf: + - $ref: "./openid_widget_api.yaml" + properties: + state: + type: string + enum: ["allowed", "blocked", "request"] + description: |- + The state of the request, as defined above. + example: "allowed" + required: + - state diff --git a/api/widgets/definitions/jitsi_data.yaml b/api/widgets/definitions/jitsi_data.yaml new file mode 100644 index 00000000000..fb43dc92b43 --- /dev/null +++ b/api/widgets/definitions/jitsi_data.yaml @@ -0,0 +1,41 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: JitsiWidgetData +description: |- + Definition for a widget's ``data`` when using a ``type`` of ``m.jitsi``. +properties: + domain: + type: string + description: |- + The Jitsi Meet domain where the conference is to be hosted. + example: "meet.jit.si" + conferenceId: + type: string + description: |- + The conference ID (also known as the room name) where the conference is to + be hosted on the given domain. + example: "HelloWorld" + isAudioOnly: + type: boolean + default: false + description: |- + If true, the Jitsi Meet conference should be started as audio only ny the client + if possible. When false, the conference should be started normally (with video). + Defaults to false (normal conference) when not provided. + example: false +required: + - domain + - conferenceId diff --git a/api/widgets/definitions/openid_credentials_action.yaml b/api/widgets/definitions/openid_credentials_action.yaml new file mode 100644 index 00000000000..362b34a56a2 --- /dev/null +++ b/api/widgets/definitions/openid_credentials_action.yaml @@ -0,0 +1,56 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: OpenIDCredentialsActionBase +properties: + api: + type: string + enum: ["toWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "toWidget" + action: + type: string + enum: ["openid_credentials"] + description: "" # The enum will result in this being "Must be $0" + example: "openid_credentials" + data: + type: object + title: OpenIDCredentialsRequestData + description: |- + The state of a previous OpenID Connect credentials request with potentially + token information. + + When ``state`` is ``allowed``, several properties (defined below) are required. + They hold the same meaning and specification as their same-named properties in + the response of the Client-Server API ``/user/{userId}/openid/request_token`` + endpoint. + allOf: + - $ref: "./openid_widget_api.yaml" + properties: + state: + type: string + enum: ["allowed", "blocked"] + description: |- + Whether or not the user has allowed the widget's request to verify their + identity. + example: "allowed" + original_request_id: + type: string + description: |- + The ``requestId`` of the original ``fromWidget`` ``get_openid`` action request. + example: "11223344" + required: + - state + - original_request_id diff --git a/api/widgets/definitions/openid_credentials_action_request.yaml b/api/widgets/definitions/openid_credentials_action_request.yaml new file mode 100644 index 00000000000..e3f6ca07473 --- /dev/null +++ b/api/widgets/definitions/openid_credentials_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: OpenIDCredentialsActionRequest +description: |- + Schema definition for a ``toWidget`` API request with action of ``openid_credentials``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./openid_credentials_action.yaml" +properties: {} diff --git a/api/widgets/definitions/openid_credentials_action_response.yaml b/api/widgets/definitions/openid_credentials_action_response.yaml new file mode 100644 index 00000000000..039e8b9a08c --- /dev/null +++ b/api/widgets/definitions/openid_credentials_action_response.yaml @@ -0,0 +1,28 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: OpenIDCredentialsActionResponse +description: |- + Schema definition for a response to a ``OpenIDCredentialsActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./openid_credentials_action_request.yaml" +properties: + response: + type: object + description: |- + The response data (an empty object). + title: OpenIDCredentialsActionResponseData + example: {} diff --git a/api/widgets/definitions/openid_widget_api.yaml b/api/widgets/definitions/openid_widget_api.yaml new file mode 100644 index 00000000000..07e1927ae0f --- /dev/null +++ b/api/widgets/definitions/openid_widget_api.yaml @@ -0,0 +1,37 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: OpenIDTokenInfoInWidgetApi +properties: + access_token: + type: string + description: |- + Required when ``state`` is ``allowed``. See above for specification. + example: "SomeT0kenHere" + token_type: + type: string + description: |- + Required when ``state`` is ``allowed``. See above for specification. + example: "Bearer" + matrix_server_name: + type: string + description: |- + Required when ``state`` is ``allowed``. See above for specification. + example: "example.com" + expires_in: + type: integer + description: |- + Required when ``state`` is ``allowed``. See above for specification. + example: 3600 diff --git a/api/widgets/definitions/screenshot_action.yaml b/api/widgets/definitions/screenshot_action.yaml new file mode 100644 index 00000000000..5140ba4608b --- /dev/null +++ b/api/widgets/definitions/screenshot_action.yaml @@ -0,0 +1,32 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ScreenshotActionBase +properties: + api: + type: string + enum: ["toWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "toWidget" + action: + type: string + enum: ["screenshot"] + description: "" # The enum will result in this being "Must be $0" + example: "screenshot" + data: + type: object + description: |- + An empty data object (no request parameters). + example: {} diff --git a/api/widgets/definitions/screenshot_action_request.yaml b/api/widgets/definitions/screenshot_action_request.yaml new file mode 100644 index 00000000000..cdd97420d2c --- /dev/null +++ b/api/widgets/definitions/screenshot_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ScreenshotActionRequest +description: |- + Schema definition for a ``toWidget`` API request with action of ``screenshot``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./screenshot_action.yaml" +properties: {} diff --git a/api/widgets/definitions/screenshot_action_response.yaml b/api/widgets/definitions/screenshot_action_response.yaml new file mode 100644 index 00000000000..57d6f0ef688 --- /dev/null +++ b/api/widgets/definitions/screenshot_action_response.yaml @@ -0,0 +1,36 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: ScreenshotActionResponse +description: |- + Schema definition for a response to a ``ScreenshotActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./screenshot_action_request.yaml" +properties: + response: + type: object + description: |- + The response data. + title: ScreenshotActionResponseData + properties: + screenshot: + type: object + title: JS Blob + description: |- + A `Blob `_ containing the + screenshot. + example: '' + required: ['screenshot'] diff --git a/api/widgets/definitions/shared_props.yaml b/api/widgets/definitions/shared_props.yaml new file mode 100644 index 00000000000..41031343da8 --- /dev/null +++ b/api/widgets/definitions/shared_props.yaml @@ -0,0 +1,91 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: WidgetCommonProperties +description: |- + Common properties for widgets regardless of where they exist. +example: + $ref: "../examples/shared_props.json" +properties: + id: + type: string + description: |- + An opaque, unique, UTF-8 identifier for the widget. Uniqueness and other requirements + are defined by the widget kind. + example: "20200827_WidgetExample" + creatorUserId: + type: string + description: |- + The user ID who originally created the widget. This varies from the user who last + edited the widget, which is typically represented by the ``sender`` on events. + example: "@alice:example.org" + name: + type: string + description: A human-readable name for the widget. + example: "My Cool Widget" + type: + type: string + description: The type of widget being represented. + example: "m.custom" + url: + type: string + description: |- + The URL where the widget can be loaded, including template variables. See the + `URL Templating`_ section for more information on templating. + example: "https://example.org/my/widget.html?roomId=$matrix_room_id" + waitForIframeLoad: + type: boolean + default: true + description: |- + When true, the widget should be hidden from view until the iframe's ``onLoad`` (or + platform equivalent) event has been fired. When false, the widget should be hidden + from view until the ``content_loaded`` API action is sent by the widget. Defaults to + true. + example: true + avatar_url: + type: string + description: |- + An optional MXC URI to an image which can be used to identify the widget. Recommended + for use alongside the ``name`` and ``data.title``. + + Images SHOULD be legible at small sizes, such as 20x20 pixels. The MXC URI here should + be the source material to allow clients to use the ``/thumbnail`` endpoint on the media. + example: "mxc://example.org/aaabbbccc" + data: + type: object + title: WidgetData + description: |- + Additional metadata for the widget. The widget can receive these in their URL safely + by using template variables. Note that some widget types may result in this property + being required. + + See the `URL Templating`_ section for more information on templating. + properties: + title: + type: string + description: |- + A human-readable title for the widget primarily shown next to the widget's name. + example: "This is a witty description for the widget" + additionalProperties: true + example: { + "title": "This is a witty description for the widget", + "custom-key": "This is a custom key" + } + +required: + - id + - creatorUserId + - type + - url diff --git a/api/widgets/definitions/sticker_action.yaml b/api/widgets/definitions/sticker_action.yaml new file mode 100644 index 00000000000..ff21bb15717 --- /dev/null +++ b/api/widgets/definitions/sticker_action.yaml @@ -0,0 +1,78 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickerActionBase +properties: + api: + type: string + enum: ["fromWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "fromWidget" + action: + type: string + enum: ["m.sticker"] + description: "" # The enum will result in this being "Must be $0" + example: "m.sticker" + data: + type: object + title: StickerActionRequestData + description: |- + Information about the sticker to send. + properties: + name: + type: string + description: |- + The human-readable name for the sticker. + example: "Smiling Face" + description: + type: string + description: |- + A longer form human-readable description for the sticker. + example: "A circular emoticon smiles blankly" + content: + type: object + title: StickerActionRequestEventContent + properties: + info: + type: object + # XXX: Ideally we'd link to the image info schema, but it has a bunch of backlinks which + # the widget spec cannot support. + title: ImageInfo + description: |- + Metadata about the image referred to in ``url`` including a thumbnail + representation. This value takes the same shape as ``ImageInfo`` as + defined for ``info`` on ``m.sticker`` events. + example: { + w: 512, + h: 512, + mimetype: "image/png", + size: 102400, + thumbnail_url: "mxc://example.org/def5678", + thumbnail_info: { + w: 256, + h: 256, + mimetype: "image/png", + size: 10240 + } + } + url: + description: |- + The URL to the sticker image. This must be a valid ``mxc://`` URI. + type: string + example: "mxc://example.org/abc1234" + required: + - info + - url + required: ['content', 'name'] diff --git a/api/widgets/definitions/sticker_action_request.yaml b/api/widgets/definitions/sticker_action_request.yaml new file mode 100644 index 00000000000..a40f2e367d0 --- /dev/null +++ b/api/widgets/definitions/sticker_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickerActionRequest +description: |- + Schema definition for an API request with action of ``m.sticker``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./sticker_action.yaml" +properties: {} diff --git a/api/widgets/definitions/sticker_action_response.yaml b/api/widgets/definitions/sticker_action_response.yaml new file mode 100644 index 00000000000..92771c57273 --- /dev/null +++ b/api/widgets/definitions/sticker_action_response.yaml @@ -0,0 +1,27 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickerActionResponse +description: |- + Schema definition for a response to a ``StickerActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./sticker_action_request.yaml" +properties: + response: + type: object + description: |- + An empty response body to acknowledge the request. + example: {} diff --git a/api/widgets/definitions/stickerpicker_data.yaml b/api/widgets/definitions/stickerpicker_data.yaml new file mode 100644 index 00000000000..ac04f15c40a --- /dev/null +++ b/api/widgets/definitions/stickerpicker_data.yaml @@ -0,0 +1,21 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickerpickerWidgetData +description: |- + Definition for a widget's ``data`` when using a ``type`` of ``m.stickerpicker``. Currently no + requirements are specified. +properties: {} +example: {} diff --git a/api/widgets/definitions/sticky_action.yaml b/api/widgets/definitions/sticky_action.yaml new file mode 100644 index 00000000000..025ce3ddd6d --- /dev/null +++ b/api/widgets/definitions/sticky_action.yaml @@ -0,0 +1,40 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickyActionBase +properties: + api: + type: string + enum: ["fromWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "fromWidget" + action: + type: string + enum: ["set_always_on_screen"] + description: "" # The enum will result in this being "Must be $0" + example: "set_always_on_screen" + data: + type: object + title: StickyActionRequestData + description: |- + Details about the request to be always on screen. + properties: + value: + type: boolean + description: |- + If true, the widget should remain on screen if possible. If false, the widget + would like to use the default rendering behaviour. + example: true + required: ['value'] diff --git a/api/widgets/definitions/sticky_action_request.yaml b/api/widgets/definitions/sticky_action_request.yaml new file mode 100644 index 00000000000..85de8fb2a42 --- /dev/null +++ b/api/widgets/definitions/sticky_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickyActionRequest +description: |- + Schema definition for an API request with action of ``set_always_on_screen``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./sticky_action.yaml" +properties: {} diff --git a/api/widgets/definitions/sticky_action_response.yaml b/api/widgets/definitions/sticky_action_response.yaml new file mode 100644 index 00000000000..8c36b742660 --- /dev/null +++ b/api/widgets/definitions/sticky_action_response.yaml @@ -0,0 +1,38 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: StickyActionResponse +description: |- + Schema definition for a response to a ``StickyActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./sticky_action_request.yaml" +properties: + response: + type: object + description: |- + The response data. + title: StickyActionResponseData + properties: + success: + type: boolean + description: |- + True to indicate the client was able to honour the request, false otherwise. The client + will only be able to honour the request if the widget is requesting to be set back to + the default behaviour, or if the widget is requesting to be on screen and no other widget + has done the same already. Permission errors relating to capabilities will result in an + error response instead of this response. + example: true + required: ['success'] diff --git a/api/widgets/definitions/supported_versions_action.yaml b/api/widgets/definitions/supported_versions_action.yaml new file mode 100644 index 00000000000..f5822cb1677 --- /dev/null +++ b/api/widgets/definitions/supported_versions_action.yaml @@ -0,0 +1,32 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: SupportedVersionsActionBase +properties: + api: + type: string + enum: ["toWidget", "fromWidget"] + description: "The API for which the version request is going over." + example: "toWidget" + action: + type: string + enum: ["supported_api_versions"] + description: "" # The enum will result in this being "Must be $0" + example: "supported_api_versions" + data: + type: object + description: |- + An empty data object (no request parameters). + example: {} diff --git a/api/widgets/definitions/supported_versions_action_request.yaml b/api/widgets/definitions/supported_versions_action_request.yaml new file mode 100644 index 00000000000..e3879e1464a --- /dev/null +++ b/api/widgets/definitions/supported_versions_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: SupportedVersionsActionRequest +description: |- + Schema definition for an API request with action of ``supported_api_versions``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./supported_versions_action.yaml" +properties: {} diff --git a/api/widgets/definitions/supported_versions_action_response.yaml b/api/widgets/definitions/supported_versions_action_response.yaml new file mode 100644 index 00000000000..93615a3330c --- /dev/null +++ b/api/widgets/definitions/supported_versions_action_response.yaml @@ -0,0 +1,36 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: SupportedVersionsActionResponse +description: |- + Schema definition for a response to a ``SupportedVersionsActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./supported_versions_action_request.yaml" +properties: + response: + type: object + description: |- + The response data. + title: SupportedVersionsActionResponseData + properties: + supported_versions: + type: array + items: + type: string + description: |- + The supported Widget API versions. + example: ['0.0.1', '0.0.2', '0.1.0'] + required: ['supported_versions'] diff --git a/api/widgets/definitions/visibility_action.yaml b/api/widgets/definitions/visibility_action.yaml new file mode 100644 index 00000000000..98c38317226 --- /dev/null +++ b/api/widgets/definitions/visibility_action.yaml @@ -0,0 +1,39 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: VisibilityActionBase +properties: + api: + type: string + enum: ["toWidget"] + description: "" # The enum will result in this being "Must be $0" + example: "toWidget" + action: + type: string + enum: ["visibility"] + description: "" # The enum will result in this being "Must be $0" + example: "visibility" + data: + type: object + description: |- + Information about whether or not the widget is visible. + title: VisibilityActionRequestData + properties: + visible: + type: boolean + description: |- + True if the widget is visible to the user, false otherwise. + example: false + required: ['visible'] diff --git a/api/widgets/definitions/visibility_action_request.yaml b/api/widgets/definitions/visibility_action_request.yaml new file mode 100644 index 00000000000..f18e5d94dcc --- /dev/null +++ b/api/widgets/definitions/visibility_action_request.yaml @@ -0,0 +1,22 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: VisibilityActionRequest +description: |- + Schema definition for a ``toWidget`` API request with action of ``visibility``. +allOf: + - $ref: "./api_request.yaml" + - $ref: "./visibility_action.yaml" +properties: {} diff --git a/api/widgets/definitions/visibility_action_response.yaml b/api/widgets/definitions/visibility_action_response.yaml new file mode 100644 index 00000000000..d0862312282 --- /dev/null +++ b/api/widgets/definitions/visibility_action_response.yaml @@ -0,0 +1,27 @@ +# Copyright 2020 The Matrix.org Foundation C.I.C. +# +# 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. + +type: object +title: VisibilityActionResponse +description: |- + Schema definition for a response to a ``VisibilityActionRequest``. +allOf: + - $ref: "./api_response.yaml" + - $ref: "./visibility_action_request.yaml" +properties: + response: + type: object + description: |- + An empty response body to acknowledge the request. + example: {} diff --git a/api/widgets/examples/shared_props.json b/api/widgets/examples/shared_props.json new file mode 100644 index 00000000000..d384cc8830f --- /dev/null +++ b/api/widgets/examples/shared_props.json @@ -0,0 +1,13 @@ +{ + "creatorUserId": "@alice:example.org", + "data": { + "custom-key": "This is a custom key", + "title": "This is a witty description for the widget" + }, + "id": "20200827_WidgetExample", + "name": "My Cool Widget", + "type": "m.custom", + "url": "https://example.org/my/widget.html?roomId=$matrix_room_id", + "waitForIframeLoad": true, + "avatar_url": "mxc://example.org/aaabbbccc" +} diff --git a/changelogs/widgets.rst b/changelogs/widgets.rst new file mode 100644 index 00000000000..e69de29bb2d diff --git a/changelogs/widgets/newsfragments/.gitignore b/changelogs/widgets/newsfragments/.gitignore new file mode 100644 index 00000000000..b722e9e13ef --- /dev/null +++ b/changelogs/widgets/newsfragments/.gitignore @@ -0,0 +1 @@ +!.gitignore \ No newline at end of file diff --git a/changelogs/widgets/pyproject.toml b/changelogs/widgets/pyproject.toml new file mode 100644 index 00000000000..cc4c62b2e22 --- /dev/null +++ b/changelogs/widgets/pyproject.toml @@ -0,0 +1,35 @@ +[tool.towncrier] + filename = "../widgets.rst" + directory = "newsfragments" + issue_format = "`#{issue} `_" + title_format = "{version}" + + [[tool.towncrier.type]] + directory = "breaking" + name = "Breaking Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations" + showcontent = true + + [[tool.towncrier.type]] + directory = "new" + name = "New Endpoints" + showcontent = true + + [[tool.towncrier.type]] + directory = "removal" + name = "Removed Endpoints" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Backwards Compatible Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "clarification" + name = "Spec Clarifications" + showcontent = true diff --git a/event-schemas/examples/m.widget b/event-schemas/examples/m.widget new file mode 100644 index 00000000000..817408f288d --- /dev/null +++ b/event-schemas/examples/m.widget @@ -0,0 +1,8 @@ +{ + "$ref": "core/state_event.json", + "type": "m.widget", + "state_key": "20200827_WidgetExample", + "content": { + "$ref": "../../../api/widgets/examples/shared_props.json" + } +} diff --git a/event-schemas/examples/m.widgets b/event-schemas/examples/m.widgets new file mode 100644 index 00000000000..623c19bf5c4 --- /dev/null +++ b/event-schemas/examples/m.widgets @@ -0,0 +1,14 @@ +{ + "$ref": "core/event.json", + "type": "m.widgets", + "content": { + "20200827_WidgetExample": { + "type": "m.widget", + "state_key": "20200827_WidgetExample", + "sender": "@alice:example.org", + "content": { + "$ref": "../../../api/widgets/examples/shared_props.json" + } + } + } +} diff --git a/event-schemas/schema/m.widget b/event-schemas/schema/m.widget new file mode 100644 index 00000000000..4ac4af98e51 --- /dev/null +++ b/event-schemas/schema/m.widget @@ -0,0 +1,18 @@ +--- +allOf: + - $ref: core-event-schema/state_event.yaml +description: Defines a room widget. The event's content is ``WidgetCommonProperties``. +properties: + content: + allOf: + - $ref: ../../api/widgets/definitions/shared_props.yaml + - title: EventContent # We use an explicit name so the rendering makes sense + type: object + state_key: + description: The ID for the widget. + type: string + type: + enum: + - m.widget + type: string +type: object diff --git a/event-schemas/schema/m.widgets b/event-schemas/schema/m.widgets new file mode 100644 index 00000000000..dc6af35dc19 --- /dev/null +++ b/event-schemas/schema/m.widgets @@ -0,0 +1,33 @@ +--- +allOf: + - $ref: core-event-schema/event.yaml +description: Defines all of the user's account widgets as a map of widget ID to ``AccountWidget``. +properties: + content: + type: object + additionalProperties: + type: object + title: AccountWidget + properties: + type: + enum: ['m.widget'] + type: string + state_key: + type: string + description: The widget's ID. + sender: + type: string + description: The current user's ID. + content: + allOf: + - $ref: ../../api/widgets/definitions/shared_props.yaml + required: + - type + - state_key + - sender + - content + type: + enum: + - m.widgets + type: string +type: object diff --git a/scripts/gendoc.py b/scripts/gendoc.py index 7e68ccd7348..4874bc66aee 100755 --- a/scripts/gendoc.py +++ b/scripts/gendoc.py @@ -530,6 +530,10 @@ def extract_major(s): "--identity_release", "-i", action="store", default="unstable", help="The identity service release tag to generate, e.g. r1.2" ) + parser.add_argument( + "--widgets_release", "-w", action="store", default="unstable", + help="The widget release tag to generate, e.g. r1.2" + ) parser.add_argument( "--list_targets", action="store_true", help="Do not update the specification. Instead print a list of targets.", @@ -556,6 +560,7 @@ def extract_major(s): "%APPSERVICE_RELEASE_LABEL%": args.appservice_release, "%IDENTITY_RELEASE_LABEL%": args.identity_release, "%PUSH_GATEWAY_RELEASE_LABEL%": args.push_gateway_release, + "%WIDGETS_RELEASE_LABEL%": args.widgets_release, } exit (main(args.target or ["all"], args.dest, args.nodelete, substitutions)) diff --git a/scripts/templating/matrix_templates/units.py b/scripts/templating/matrix_templates/units.py index ff614e34a2f..bc00a6ab372 100644 --- a/scripts/templating/matrix_templates/units.py +++ b/scripts/templating/matrix_templates/units.py @@ -42,6 +42,7 @@ os.path.join(matrix_doc_dir, "api/identity"): "is", os.path.join(matrix_doc_dir, "api/push-gateway"): "push", os.path.join(matrix_doc_dir, "api/server-server"): "ss", + os.path.join(matrix_doc_dir, "api/widgets"): "widgets", } SWAGGER_DEFINITIONS = { os.path.join(matrix_doc_dir, "api/application-service/definitions"): "as", @@ -49,6 +50,7 @@ os.path.join(matrix_doc_dir, "api/identity/definitions"): "is", os.path.join(matrix_doc_dir, "api/push-gateway/definitions"): "push", os.path.join(matrix_doc_dir, "api/server-server/definitions"): "ss", + os.path.join(matrix_doc_dir, "api/widgets/definitions"): "widgets", } EVENT_EXAMPLES = os.path.join(matrix_doc_dir, "event-schemas/examples") EVENT_SCHEMA = os.path.join(matrix_doc_dir, "event-schemas/schema") @@ -204,6 +206,11 @@ def get_json_schema_object_fields(obj, enforce_title=False): logger.debug("Processing object with title '%s'", obj_title) additionalProps = obj.get("additionalProperties") + + # When 'additionalProps: true` is defined, it should be treated as a freeform object + if additionalProps == True: + additionalProps = dict(type="object", title="value") + props = obj.get("properties") if additionalProps and not props: # not "really" an object, just a KV store @@ -788,6 +795,7 @@ def load_apis(self, substitutions): is_ver = substitutions.get("%IDENTITY_RELEASE_LABEL%", "unstable") as_ver = substitutions.get("%APPSERVICE_RELEASE_LABEL%", "unstable") push_gw_ver = substitutions.get("%PUSH_GATEWAY_RELEASE_LABEL%", "unstable") + widget_ver = substitutions.get("%WIDGET_RELEASE_LABEL%", "unstable") # we abuse the typetable to return this info to the templates return TypeTable(rows=[ @@ -811,6 +819,10 @@ def load_apis(self, substitutions): "`Push Gateway API `_", push_gw_ver, "Push notifications for Matrix events", + ), TypeTableRow( + "`Widgets `_", + widget_ver, + "Client-side embedded applications", ), ]) @@ -970,6 +982,7 @@ def load_changelogs(self, substitutions): "client_server": substitutions.get("%CLIENT_RELEASE_LABEL%", "unstable"), "identity_service": substitutions.get("%IDENTITY_RELEASE_LABEL%", "unstable"), "push_gateway": substitutions.get("%PUSH_GATEWAY_RELEASE_LABEL%", "unstable"), + "widgets": substitutions.get("%WIDGETS_RELEASE_LABEL%", "unstable"), "application_service": substitutions.get("%APPSERVICE_RELEASE_LABEL%", "unstable"), } diff --git a/specification/targets.yaml b/specification/targets.yaml index df66218f6c0..88137149b35 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -25,6 +25,10 @@ targets: files: - push_gateway.rst version_label: "%PUSH_GATEWAY_RELEASE_LABEL%" + widgets: + files: + - widgets.rst + version_label: "%WIDGETS_RELEASE_LABEL%" rooms@v1: # this is translated to be rooms/v1.html files: - rooms/v1.rst diff --git a/specification/widgets.rst b/specification/widgets.rst new file mode 100644 index 00000000000..a9a3b56541d --- /dev/null +++ b/specification/widgets.rst @@ -0,0 +1,772 @@ +.. Copyright 2020 The Matrix.org Foundation C.I.C. +.. +.. 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. + +Widgets +======= + +{{unstable_warning_block_WIDGETS_RELEASE_LABEL}} + +Widgets are client-side embedded applications which can communicate with Matrix clients. Widgets +are often used to present information to users and allow them to more interactively collaborate. + +Due to platform constraints, unreasonable implementation effort, and client-specific design choices, +widgets are optional in Matrix. Clients are encouraged to support widgets if possible and reasonable, +though degraded behaviour, such as "open in browser" links, is considered acceptable by this +specification. + +.. contents:: Table of Contents +.. sectnum:: + +Changelog +--------- + +.. topic:: Version: %WIDGETS_RELEASE_LABEL% +{{widgets_changelog}} + +This version of the specification is generated from +`matrix-doc `_ as of Git commit +`{{git_version}} `_. + +For the full historical changelog, see +https://github.com/matrix-org/matrix-doc/blob/master/changelogs/widgets.rst + +Other versions of this specification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following other versions are also available, in reverse chronological order: + +- `HEAD `_: Includes all changes since the latest versioned release. + +API Standards +------------- + +Throughout this specification, a "client" is referred to as something which is rendering/supporting +("hosting") widgets. Widgets are unique in that they can be considered a client when referred to in +a typical network setting, though this specification ensures that a widget is always referred to as +a "widget" and the term "client" is solely reserved for the widget's host application. Note that +widgets can be hosts to widgets - deciphering which role is which in this context is left as an +exercise for the reader. + +The mandatory baseline for a widget is a typical website with the optional communication protocol +described here. When communicating with a Matrix client, the mandatory baseline is the `JavaScript +postMessage API `_ using the +protocol described by this specification. In the future more accessible transports for clients will +be considered as optional extensions, such as using operating system-specific hooks. + +All objects exchanged over the Widget (``postMessage``) API are JSON objects. + +In essence, widgets are typically iframes or the platform equivilant to a website which are accessible +in the client. + +All of the schemas in this specification are intended to be referenced by name, and thus can safely +be used in auto-generated implementations which rely on stable naming. + +Widget Kinds +------------ + +Widgets currently can exist in the following places: + +* Within rooms, accessible by members/observers of the room. +* For a particular user, accessible only by that user. + +{{definition_widgets_shared_props}} + +Room Widgets +~~~~~~~~~~~~ + +Room widgets are defined by state events in the room, and are as such accessible to anyone who is +able to see the state of the room. Widgets can individually apply additional access restrictions +such as preventing non-joined members of the room from accessing the widget's functionality. + +Clients MUST NOT show room widgets to the user unless the user is viewing that room or unless the +widget has set an appropriate always-on-screen request through the Widget API. + +The ``state_key`` for a room widget MUST match the widget's ``id``. Due to this association, new +widgets in the room must use a unique ``state_key`` (and therefore ``id``). Widgets can be +updated by sending a new state event for the widget's ``state_key``. + +Invalid room widgets MUST NOT be shown to users. This is also how widgets are removed from a room: +send a new state event for the same widget ID with at least the ``url`` and/or ``type`` missing +from the event content. Once Matrix allows for state events to be properly deleted then doing so +to the widget state event will be just as valid to remove it from the room. + +.. WARNING:: + Do not store sensitive information such as tokens, secrets, or passwords + in the widget data as it can be viewed by anyone who can see the room state. + +{{m_widget_event}} + +Account Widgets +~~~~~~~~~~~~~~~ + +Account widgets are defined in the user's account data, and are as such only visible to them. +Widgets can individually apply additional access restrictions as needed. Account widgets are +not linked to any particular room. + +Account widgets are represented under the ``m.widgets`` account data event as a map of widget ID +to definition. As such, the widget's ``id`` must be unique within this object's properties. The +definition for an account widget is nearly equivilant to a room widget's state event representation, +using the ``type``, ``state_key``, ``sender``, and ``content`` fields of the state event. + +Account widgets can be added by adding a new key to the ``m.widgets`` account data, edited by +modifying the appropriate ``AccountWidget`` definition, or deleted by simply removing the appropriate +property from the ``m.widgets`` acount data. + +.. WARNING:: + Do not store sensitive information such as tokens, secrets, or passwords + in the widget data as it is not secure or encrypted. + +{{m_widgets_event}} + + +Rendering +--------- + +Widgets SHOULD be rendered using an iframe or platform equivilant. Clients can use platform-specific +rendering for widgets if they are confident in being able to do so, such as in the case of most +video conference widgets. + +Clients SHOULD ask for permission to load a widget from the user prior to presenting the widget. If +the user was the last ``sender`` of a widget (not the ``creatorUserId``), the prompt can be skipped. +This prompt is strongly encouraged to ensure that users do not inadvertently send their information +to a third party. Private information such as the user's name, avatar, or IP address can be sent as +a result of how widgets work, and thus clients should attempt to prevent users from sending this +information unknowingly. + +URL Templating +~~~~~~~~~~~~~~ + +The widget's URL is a template of what the client should render and should never be parsed by the +client to determine what the parameters are. All widgets make use of the ``data`` object to store +configuration-like values, which is also where clients should inspect for values needed to render +any UI. + +Variable names for the template are the keys of the ``data`` object, with the values being the same +values of the object. Variables are included unencoded in the URL for population by the client, which +MUST use appropriate escaping to ensure the URL will be as valid as possible. + +For example, given a ``data`` object like this:: + + { + "hello": "world", + "answer": 42 + } + +and a ``url`` of ``https://example.com?var1=$hello&answer=$answer`` the client MUST come up with +a URL of ``https://example.com?var1=world&answer=42`` to render. Complex types, such as objects and +arrays, for variable values do not have defined behaviour - widget creators are encouraged to stick +to "simple" types like numbers, strings, and booleans. Template variables can appear anywhere in the +URL. + +Nested variables are not supported, and as such clients should be careful in their templating +approach. For example, if ``hello`` in the above example ``data`` was set to ``$answer``, the literal +value ``$answer`` would be included in the widget URL rather than ``42``. + +As mentioned, clients must also encode values on behalf of the widget creator to maintain a valid +URL as much as possible. For example, ``test:value`` could become ``test%3Avalue`` when used as a +template variable value. + +A few default variables, which MUST take priority over the same names in ``data``, are: + +* ``matrix_user_id`` - The current user's ID. +* ``matrix_room_id`` - The room ID the user is currently viewing, or an empty string if none applicable. +* ``matrix_display_name`` - The current user's display name, or user ID if not set. +* ``matrix_avatar_url`` - The current user's avatar URL as reported in their profile, or and empty + string if not present. This shouldn't be the ``mxc://`` form of the user's avatar, but instead the + full HTTP URL to the ``/media/download`` endpoint for their avatar from the Client-Server API. +* ``matrix_widget_id`` - The widget's ID to allow the widget to communicate effectively with the client. + +.. WARNING:: + The ``matrix_user_id`` variable MUST NOT be assumed to be the current authenticated user due to + how trivial it is to provide false details with. Widgets which need to store per-user details + or private information will need to verify the user's identity in some other way. + +Security Considerations +~~~~~~~~~~~~~~~~~~~~~~~ + +Clients SHOULD check to ensure that widgets are valid URLs *after* templating but *before* rendering +or asking for permission to load. Invalid URLs from the client's perspective should not be shown to +the user and can be treated as though no ``url`` was present (i.e.: a deleted/invalid widget). + +Clients MUST NOT attempt to render widgets with schemes other than ``http:`` and ``https:``. Widgets +using alternative schemes, including template variables as schemes, are considered invalid and thus +should be ignored. This is to prevent widget creators from using ``javascript:`` or similar schemes +to gain access to the user's data. + +Clients SHOULD apply a sandbox to their iframe or platform equivilant to ensure the widget cannot +get access to the data stored by the client, such as access tokens or cryptographic keys. More +information on origin restrictions is in the Widget API's security considerations section. + +Clients should be aware of a potential `CSRF `_ +opportunity due to clients making arbitrary ``GET`` requests to URLs. Typical sites should not +be using ``GET`` as a state change method, though it is theoretically possible. + +Widget Types +------------ + +A widget's ``type`` can be one of the following specified types or a custom type which preferably +uses the Java package naming convention as a namespace. Types prefixed with the ``m.`` namespace +are reserved by this specification. + +Besides the ``type`` itself, widget types influence the widget's ``data`` by requiring specified +keys to exist. It is expected that the widget will use these keys as variables for their URL, though +this specification does not require such behaviour. Clients SHOULD treat widgets without the +required ``data`` properties for the types specified here as invalid widgets, thus not rendering +them. + +Clients MUST treat widgets of unknown types as ``m.custom``, unless it is impossible for the client +to render the widget kind in that way. For example, custom widgets at the per-user rather than +per-room level might not be possible and thus can be treated as invalid (ignored). + +Clients are not required to support all of these widget types (with the implied exception of +``m.custom``) as they can all be safely represented as ``m.custom`` widgets. Similarly, if a +widget fails the schema requirements for its ``type`` then it should be treated as ``m.custom`` +by the client. + +Custom/Basic Widgets +~~~~~~~~~~~~~~~~~~~~ + +Custom widgets are the most basic form of widget possible, and represent the default behaviour +for all widgets. They have an explicit widget ``type`` of ``m.custom``, though any +unknown/unsupported widget type for the client will be treated as a custom widget. They have +``data`` matching ``CustomWidgetData``. + +{{definition_widgets_custom_data}} + +Jitsi Meet Conferences +~~~~~~~~~~~~~~~~~~~~~~ + +`Jitsi Meet `_ conferences can be held on a per-room basis with +a widget ``type`` of ``m.jitsi`` and ``data`` matching ``JitsiWidgetData``. + +.. Note:: + Though technically possible, this widget type should not be used outside of room widgets. + +{{definition_widgets_jitsi_data}} + +Stickerpickers +~~~~~~~~~~~~~~ + +Stickerpickers are user widgets which allow the user to send ``m.sticker`` events to the current +room using the Widget API described by this specification. They have a widget ``type`` of +``m.stickerpicker`` and ``data`` which matches ``StickerpickerWidgetData``. + +.. Note:: + Though technically possible, this widget type should not be used outside of user widgets. + +{{definition_widgets_stickerpicker_data}} + +Widget Wrappers +--------------- + +Most widgets in the wild are "wrapped" with some website that provides added functionality or +handles the Widget API communications. They have no formal specification as they are implicitly +handled as part of rendering widgets. As such, they also have no specific requirements to have +any particular behaviour. + +A wrapper typically appears on a widget as a ``url`` pointing to a resource which then embeds +the content within another iframe. This allows the widget to be gated by authentication or be +more easily embedded within Matrix (as would be the case for Spotify and similar widgets - the +content to be embedded does not translate directly to a Matrix widget and instead needs a bit +of help from a wrapper to embed nicely). + +Widget API +---------- + +The widget API is a bidirectional communication channel between the widget and the client, initiated +by either side. This communication happens over the `JavaScript postMessage API +`_. + +The API is split into two parts: ``fromWidget`` (widget -> client) and ``toWidget`` (client -> widget). +Both have the same general API shape: A request, called an ``action``, is sent to the other party +using the ``WidgetApiRequest`` schema. The other party then processes the request and returns an +object matching ``WidgetApiResponse``. + +All communication is done within a "session", where the first message sent to either side indicates +the start of the session. Only the client can close/terminate a session by unloading/reloading the +widget. + +The ``data`` of a ``WidgetApiRequest`` varies depending on the ``action`` of the request, as does the +``response`` of a ``WidgetApiResponse``. + +{{definition_widgets_api_request}} + +{{definition_widgets_api_response}} + +Timeouts +~~~~~~~~ + +All requests sent over the API require a response from the other side, even if the response is to +just acknowledge that the request happened. Both widgets and clients should implement timeouts on +their requests to avoid them hanging forever. The default recommended timeout is 10 seconds, after +which the request should be considered not answered and failed. Requests can be retried if they are +failed, though some actions do not lend themselves well to idempotency. + +Error Handling +~~~~~~~~~~~~~~ + +When the receiver fails to handle a request, it should acknowledge the request with an error response. +Note that this doesn't include timeouts, as the receiver will not have had an error processing the +request - it simply did not receive it in time. + +An error response takes the shape of a ``WidgetApiErrorResponse``. + +{{definition_widgets_api_error}} + +Versioning +~~~~~~~~~~ + +The Widget API version tracks the version of this specification (``r0.1.0`` is Widget API version +``0.1.0``, for example). Both widgets and clients can perform a request with action of +``supported_api_versions`` (``SupportedVersionsActionRequest``) to get the other side's list of +supported versions (``SupportedVersionsActionResponse``). The sender SHOULD NOT use actions which +are unsupported by the intended destination. In the event that the sender and destination cannot +agree on a supported version, either side should abort their continued execution + +Actions in this specification list which version they were introduced in for historical purposes. +Actions will always be backwards compatible with prior versions of the specification, though the +specification from time to time may add/remove actions as needed. + +In order for a widget/client to support an API version, it MUST implement all actions supported +by that version. For clarity, all actions presented by this document at a given version are +supported by that version. Implicitly, the actions to request supported API versions are mandatory +for all implementations. + +.. Note:: + For historical purposes, ``0.0.1`` and ``0.0.2`` are additionally valid versions which implement + the same set as ``0.1.0`` (the first version of this specification). + +{{definition_widgets_supported_versions_action_request}} + +{{definition_widgets_supported_versions_action_response}} + +Initiating Communication +~~~~~~~~~~~~~~~~~~~~~~~~ + +Immediately prior to rendering a widget, the client MUST prepare itself to handle communications +with the widget. Typically this will result in setting up appropriate event listeners for the +API requests. + +If the widget was set up with ``waitForIframeLoad: false``, the widget will initiate the +communication by sending a ``fromWidget`` request with ``action`` of ``content_loaded`` (see below). +If ``waitForIframeLoad`` was ``true``, the client will initiate communication once the iframe or +platform equivilant has loaded successfully (see ``waitForIframeLoad``'s description). + +Once the client has established that the widget has loaded, as defined by ``waitForIframeLoad``, +it initiates a capabilities negotiation with the widget. This is done using the ``capabilities`` +action on the ``toWidget`` API. + +The capabilities negotiated set the stage for what the widget is allowed to do within the session. +Clients MUST NOT re-negotiate capabilities after the session has been established. + +Prior to the session being initiated, neither side should be sending actions outside of those +required to set up the session. Version checking can happen at any time by either side, though +the initiator of the session should be left responsible for the first version check. For example, +if the client is waiting for a ``content_loaded`` action then the widget should be the one to +request the supported API versions first. Once a version check has been started by one side, it is +implied that the other side can do the same. + +A broad sequence diagram for ``waitForIframeLoad: false`` is as follows:: + + +---------+ +---------+ + | Client | | Widget | + +---------+ +---------+ + | | + | Render widget | + |-------------- | + | | | + |<------------- | + | | + | `supported_api_versions` request | + |<------------------------------------------| + | | + | `supported_api_versions` response | + |------------------------------------------>| + | | + | `supported_api_versions` request | + |------------------------------------------>| + | | + | `supported_api_versions` response | + |<------------------------------------------| + | | + | `content_loaded` request | + |<------------------------------------------| + | | + | Acknowledge `content_loaded` request | + |------------------------------------------>| + | | + | `capabilities` request | + |------------------------------------------>| + | | + | `capabilities` response | + |<------------------------------------------| + | | + | Approve/deny capabilities | + |-------------------------- | + | | | + |<------------------------- | + | | + +A broad sequence diagram for ``waitForIframeLoad: true`` is as follows:: + + +---------+ +---------+ + | Client | | Widget | + +---------+ +---------+ + | | + | Render widget | + |-------------- | + | | | + |<------------- | + | | + | | iframe loading + | |--------------- + | | | + | |<-------------- + | | + | Implicit `onLoad` event from iframe | + |<-----------------------------------------| + | | + | `supported_api_versions` request | + |----------------------------------------->| + | | + | `supported_api_versions` response | + |<-----------------------------------------| + | | + | `supported_api_versions` request | + |<-----------------------------------------| + | | + | `supported_api_versions` response | + |----------------------------------------->| + | | + | `capabilities` request | + |----------------------------------------->| + | | + | `capabilities` response | + |<-----------------------------------------| + | | + | Approve/deny capabilities | + |-------------------------- | + | | | + |<------------------------- | + | | + +After both sequence diagrams, the session has been successfully established and can continue as +normal. + +Verifying Capabilities +++++++++++++++++++++++ + +The client MUST have a mechanism to approve/deny capabilities. This can be done within the client's +code, not involving the user, by using heuristics such as the origin and widget type, or it can be +done by involving the user with a prompt to approve/deny particular capabilities. + +The capabilities negotiation does not specify a way for the client to indicate to the widget which +capabilities were denied. The widget SHOULD only request the bare minimum required to function and +assume that it will receive all the requested capabilities. Clients SHOULD NOT automatically approve +all requested capabilities from widgets. + +Whenever a widget attempts to do something with the API which requires a capability it was denied, +the client MUST respond with an error response indicating as such. + +Any capabilities requested by the widget which the client does not recognize MUST be denied +automatically. Similarly, a client MUST NOT send requests to a widget which require the widget +to have been aprroved for a capability that it was denied access to. Clients MUST NOT approve +capabilities the widget did not request - these are implicitly denied. + +A complete list of capabilities can be found in the `Available Capabilities`_ section. + +Available Capabilities +~~~~~~~~~~~~~~~~~~~~~~ + +The following capabilities are defined by this specification. Custom capabilities can only be +defined via a namespace using the Java package naming convention. + +Screenshots ++++++++++++ + +``m.capbility.screenshot`` can be requested by widgets if they support screenshots being taken +of them via the ``screenshot`` action. Typically this is only used to verify that the widget API +communications work between a client and widget. Widgets cannot use this capability to initiate +screenshots being taken of them - clients must request screenshots with the ``screenshot`` action. + +Sticker Sending ++++++++++++++++ + +``m.sticker`` can be requested by widgets if they would like to send stickers into the room the +user is currently viewing. This should be implicitly approved by clients for ``m.stickerpicker`` +widgets. + +Always On Screen +++++++++++++++++ + +``m.always_on_screen`` can be requested by widgets if they would like to be able to use the +``set_always_on_screen`` action. This should be implicitly approved by clients for ``m.jitsi`` +widgets (see the action's spec for more information). + +OpenID Connect Authentication +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Widgets can request OpenID Connect credentials from the client (which in turn requests them from the +homeserver) to validate that the current user is who they say they are. The credentials are validated +out of band from the client to ensure the client is not able to falsify them. + +There is no required capability for using this flow, however clients SHOULD prompt the user to +approve the widget's request to validate their identity. This prompt can have a "always remember for +this widget"-style checkbox on it, which is supported by the API exchange. Including the user in the +approval prompt does mean that the request is at risk of timing out, and as such there is a two part +exchange involving the client and widget. + +The request is always initiated by the widget using the ``fromWidget`` ``get_openid`` action. This +is either responded to immediately with an OpenID Connect token, an indication of the request being +blocked, or an indication that the user is making a decision. When a user makes a selection, the +client uses the ``toWidget`` API to send a ``openid_credentials`` action with the relevant state. + +After the widget receives the token from the client, it should validate it with the federation API. +Typically this means handing it off to a backend service which will validate the token and return +another credential the widget can use for future requests. + +.. WARNING:: + Like with the OpenID Connect endpoints described by the Client-Server API and Federation API, it + is important that the widget ensure the user ID returned by the server matches the server name + given in the token from the client. + +When needed, the client MUST call ``/_matrix/client/%CLIENT_MAJOR_VERSION%/user/{userId}/request_token`` +to get the needed token to pass through to the widget. + +A typical diagram of this flow is:: + + +-------+ +---------+ +---------+ +---------------+ +-------------+ + | User | | Client | | Widget | | WidgetBackend | | Homeserver | + +-------+ +---------+ +---------+ +---------------+ +-------------+ + | | | | | + | | Establish Widget API session | | | + | |----------------------------------------->| | | + | | | | | + | | Establish Widget API session | | | + | |<-----------------------------------------| | | + | | | | | + | | fromWidget get_openid request | | | + | |<-----------------------------------------| | | + | | | | | + | | ack with state "request" | | | + | |----------------------------------------->| | | + | | | | | + | Ask if the widget can verify their identity | | | | + |<-------------------------------------------------| | | | + | | | | | + | Approve | | | | + |------------------------------------------------->| | | | + | | | | | + | | Call /_matrix/client/{version}/user/{userId}/request_token | | + | |-------------------------------------------------------------------------------------------------------------------------------------------------------->| + | | | | | + | | | | OpenID Connect token | + | |<--------------------------------------------------------------------------------------------------------------------------------------------------------| + | | | | | + | | toWidget openid_credentials request | | | + | |----------------------------------------->| | | + | | | | | + | | ack with empty response object | | | + | |<-----------------------------------------| | | + | | | | | + | | | Send received token for validation | | + | | |------------------------------------------->| | + | | | | | + | | | | Federated call to /_matrix/federation/v1/openid/userinfo | + | | | |---------------------------------------------------------------->| + | | | | | + | | | | User information | + | | | |<----------------------------------------------------------------| + | | | | | + | | | | Verify returned user information | + | | | |--------------------------------- | + | | | | | | + | | | |<-------------------------------- | + | | | | | + | | | Successful validation response | | + | | |<-------------------------------------------| | + | | | | | + +``toWidget`` API +~~~~~~~~~~~~~~~~~~ + +The ``toWidget`` API is reserved for communications from the client to the widget. Custom +actions can be defined by using the Java package naming convention as a namespace. + +Capabilities +++++++++++++ + +:Introduced in: ``0.1.0`` + +As part of the capabilities negotiation, the client sends a request with an action of +``capabilities`` (``CapabilitiesActionRequest``) to the widget, which replies with the requested +set of capabilities (``CapabilitiesActionResponse``). + +{{definition_widgets_capabilities_action_request}} + +{{definition_widgets_capabilities_action_response}} + +Screenshots ++++++++++++ + +:Introduced in: ``0.1.0`` + +If the widget is approved for use of the ``m.capbility.screenshot`` capability, the client can +send a ``screenshot`` action (``ScreenshotActionRequest``) to request an image from the widget +(returned as a ``ScreenshotActionResponse``). + +.. Note:: + This is typically only used to verify that communication is working between the widget and client. + +.. WARNING:: + Widgets have an ability to send extremely large files and non-images via this action. Clients + should only enable support for screenshots in a trusted environment, such as when a widget + developer is making use of the client to test their widget. + +{{definition_widgets_screenshot_action_request}} + +{{definition_widgets_screenshot_action_response}} + +Widget Visibility ++++++++++++++++++ + +:Introduced in: ``0.1.0`` + +The client can indicate to the widget whether it is visible or not to the user with the ``visbility`` +action request (``VisibilityActionRequest``). If the widget does not receive visibility information, +it must assume that it is visible to the user. + +Typically this action is not used on room widgets as they are visible implicitly to the user when +they view that room. Account widgets, however, often get rendered in the background by the client +and thus can be hidden/shown at times. + +.. Note:: + Stickerpicker widgets and similar often make the best use of this to reload the user's available + content when the widget gets shown again. + +This action should only be sent when visibility of the widget to the user changes. + +{{definition_widgets_visibility_action_request}} + +{{definition_widgets_visibility_action_response}} + +OpenID Connect Credential Information ++++++++++++++++++++++++++++++++++++++ + +:Introduced in: ``0.1.0`` + +.. Note:: + This section assumes the reader has the prior knowledge established by the + `OpenID Connect Authentication <#openid-connect-authentication>`_ section. + +This action is used by the client to indicate that the user has made a selection regarding the +prompt to confirm if the widget can verify their identity. + +If approved, the request will contain the OpenID Connect token the widget will have to verify. If +defined, the request will indicate as such. + +{{definition_widgets_openid_credentials_action_request}} + +{{definition_widgets_openid_credentials_action_response}} + +``fromWidget`` API +~~~~~~~~~~~~~~~~~~ + +The ``fromWidget`` API is reserved for communications from the widget to the client. Custom actions +can be defined by using the Java package naming convention as a namespace. + +Indicating Content Loaded ++++++++++++++++++++++++++ + +:Introduced in: ``0.1.0`` + +In some rendering cases, the widget is expected to send a ``content_loaded`` action request taking +the shape of ``ContentLoadedActionRequest``. The widget can send this any time, even when not +required for establishing the session. Widgets SHOULD NOT send this action after the session has +been established. + +{{definition_widgets_content_loaded_action_request}} + +{{definition_widgets_content_loaded_action_response}} + +Sending Stickers +++++++++++++++++ + +:Introduced in: ``0.1.0`` + +If the widget is approved for use of the ``m.sticker`` capability, the widget can send ``m.sticker`` +action requests (``StickerActionRequest``) to have the client post an ``m.sticker`` event to the +room the user is currently viewing. If the room is encrypted, the client is responsible for +encrypting the widget's implied event. + +The stickers widgets produce MUST meet the requirements of stickers in ``m.sticker`` events. For +creating the sticker event, the client uses the ``name`` or ``description`` from the request +in the event's ``body``, and otherwise copies the ``url`` and ``info`` values from the request +to the event directly (potentially with some validation). + +{{definition_widgets_sticker_action_request}} + +{{definition_widgets_sticker_action_response}} + +Always On Screen +++++++++++++++++ + +:Introduced in: ``0.1.0`` + +If the widget is approved for use of the ``m.always_on_screen`` capability, the widget can request +that the client keep it always on screen with a ``set_always_on_screen`` action request +(``StickyActionRequest``). + +Widgets by default are *not* always on screen, and only one widget at a time can be always on the +screen. Typically this is used by video conferencing widgets to ensure that the call is not disrupted +when the user switches rooms, and as such clients SHOULD ignore the restriction regarding only +rendering widgets when the user is viewing that room while the widget has requested to be always on +screen. + +{{definition_widgets_sticky_action_request}} + +{{definition_widgets_sticky_action_response}} + +Requesting OpenID Connect Tokens +++++++++++++++++++++++++++++++++ + +:Introduced in: ``0.1.0`` + +.. Note:: + This section assumes the reader has the prior knowledge established by the + `OpenID Connect Authentication <#openid-connect-authentication>`_ section. + +This action is used by the widget to ask the client to start the OpenID Connect token exchange. +The client has three possible responses: + +* A ``state`` of ``allowed`` alongside the OpenID Connect token. This is typically used if the user + indicated that the widget is always allowed to verify their identity. +* A ``state`` of ``blocked``. This is typically used when the user has indicated that the widget + can never verify their identity. +* A ``state`` of ``request``. This indicates that the client is asking the user for permission and + will follow up with an appropriate ``toWidget`` ``openid_credentials`` request later. + + +{{definition_widgets_get_openid_action_request}} + +{{definition_widgets_get_openid_action_response}} + +Security Considerations +~~~~~~~~~~~~~~~~~~~~~~~ + +The Widget API can allow for significant control of a client/widget, and thus needs to be secured +as much as possible. Clients should refuse/ignore requests and responses from origins other than +the widget's rendered origin, and should verify that the widget ID matches the expected value. +Widgets have a harder time of determining the origin, though they can rely on techniques like +``window.parent`` to ensure they are talking/responding to the right place.