MSC3009: Websocket widget transport

travis/msc/widgets-http-transport
Travis Ralston 3 years ago
parent de2aa0c3aa
commit d77f9b88c1

@ -0,0 +1,110 @@
# MSC3009: Websocket transport for client <--> widget communications
If a widget wishes to speak with a client (or a client with a widget) then the implementation must
support postmessage as a capability, however not all scenarios for widgets make this possible. For
example, mobile apps and thinly wrapped widgets may not have enough JavaScript available to handle
the postmessage API.
*Note*: A thinly wrapped widget is one which is in a theoretical web view which disconnects the widget
from the client, for clients which cannot reasonably support a webview or similar. This is primarly
a solution for desktop clients, which puts the actual client and widget in different processes (the
desktop app running on its own with the widget running in a web browser after being 'popped out').
## Proposal
A websocket transport is defined in addition to the existing postmessage API support. This alternative
transport is opt-in by the client for the widget to handle. The API over postmessage is quite simply
the same as the postmessage API but with the added implicit behaviour that `waitForIframeLoad` is `false`
(this causes the client to wait for the widget to reach out to the client instead of the client
assuming the widget has loaded).
Because there would be two transports available, clients need to know which ones are available on
the widget, and the widget should not be required to implement them all. This proposal opens up an
opportunity for custom transports through a namespaced array of transports being listed on the standardized
widget definition:
```json5
{
"type": "m.custom",
"url": "http://localhost:8082#?widgetId=$matrix_widget_id&transport=$matrix_widget_transport",
"name": "Widget Debugger",
"avatar_url": "mxc://t2bot.io/c977fc5396241194e426e6eb9da64f025f813f1b",
"data": {
"title": "Widget testing"
},
"creatorUserId": "@travis:localhost",
"id": "debugger_test",
// This is the only added field.
"transports": [
"m.postmessage",
"m.websockets"
]
}
```
If the `transports` array is empty, undefined, or the wrong data type then the client will assume that
the widget definition meant `["m.postmessage"]` for a value. If the array contains no known transports
to communicate with the widget, the client will assume the widget supports `m.postmessage` as a baseline.
This means `m.postmessage` remains the bare minimum every widget must support.
Prior to rendering the widget, the client picks the transport and spins up any applicable servers (websocket
receivers, etc) for the widget to communicate with. The client communicates the transport it chose with
an available `$matrix_widget_transport` template variable.
When the `m.websockets` transport is chosen, a `$matrix_websocket_uri` template variable is made available
by the client containing the `ws://` URI for the widget to connect to. Because the widget is expected to
make first contact, the client should already be listening and not try to connect to the widget.
## Rationale for websockets
Websockets are bidirectional and about as easy as HTTP to set up and deploy in modern applications. Most
use cases will see local clients spinning up servers and therefore the complexities of corporate firewalls
should not apply.
However, using websockets means that the widget cannot be contacted and is assumed to reach out to the client
first. This could potentially leave the client in an unknown state where it is waiting for the widget to reach
out, but the widget died or refuses to do so. Reconnection attempts by the widget may also be confusing to
the client (client restarts but widget doesn't, or local network issues) - **this has undefined behaviour
under this MSC currently.**
## Potential issues
Web clients (and widgets) will not be able to create websocket servers to listen for requests from widgets,
making this MSC targeted specifically at desktop/mobile clients which are typically more able to do so.
Web clients in particular are likely to need their own alternative transport for cases when the widget
is popped out of the client's context, such as in a new tab.
This MSC also introduced capabilities for arbitrary alternative transports. This isn't necessarily seen
as a bad thing, though could lead to fragmentation among the widget authoring community. This MSC attempts
to mitigate that fragmentation by maintaining a baseline transport.
There is also a question if this is even needed: if [MSC3008 - Scoped access](https://github.com/matrix-org/matrix-doc/pull/3008)
were to be accepted, the only remaining functionality would be the capabilities API (for which few capabilities
are useful in this use case) and other smaller client manipulation MSCs. Given the widget is separated from
the client, it may not be desirable to support [MSC2931 - matrix.to navigation](https://github.com/matrix-org/matrix-doc/pull/2931)
over this alternative transport, for example. Similarly, there is nothing to pin to the screen and therefore
the widget's attempts to request an "always on screen" capability would be for naught.
## Alternatives
Regular HTTP might also work, as would Server-Sent Events, though these are inherently one-way or require
excessive resources to make two-way. Other efficient transports are not easily available on all platforms,
such as lower level TCP/UDP-based transports.
## Security considerations
There is a high likelihood that when a client spins up a websocket server that it'll be bound to localhost
without TLS. This could be problematic if widgets are transferring sensitive information over the API
which could be intercepted by local processes. This is akin to a malicious browser extension listening for
postmessage requests on `*`, however.
## Unstable prefix
The `transports` array becomes `org.matrix.msc3009.transports` while this MSC is not considered stable. The
template variables `$matrix_widget_transport` and `$matrix_websocket_uri` become `$org.matrix.msc3009.widget_transport`
and `$org.matrix.msc3009.websocket_uri` respectively.
The transports become `org.matrix.msc3009.postmessage` and `org.matrix.msc3009.websockets`. Communication
over either transport is not required to be namespaced in any particular way, however any unstable actions
over the widget API must be appropriately prefixed.
Loading…
Cancel
Save