.. _specification: ============= Specification ============= 1. Overview =========== Iconet is about presenting content from foreign sources in situation where a client is not able to present this content with native means. This document and subdocuments linked here will guide you through the process of supporting interconnectivity. The walkthrough comprises the following steps: 1. To begin with, a packet is sent to a client that does not have the capabilities to display / present it to the user. 2. The packet however has iconet-(meta)data attached which the client can use as a fallback. The data required is described in section :ref:`2. Required Iconet Data for a Packet `. The iconet data may also provide the packet in additional formats. 3. The iconet data includes information that allows the client to render a presentation from the packet (using :ref:`fallback-iframes `) and optionally :ref:`translate ` the packet to different formats. Note, that packet content (dynamic & private) is intentionally separated from the fallback iframe data (static & public). See section :ref:`3. Interpreter Manifests `. 4. The presentation is rendered (or translated) with a fallback-iframe. Fallback-iframes and the communication flow between the fallback-iframe and the embedding application, as well as sandboxing, is described in section :ref:`4. Fallback-iframes `. 5. Last but not least - some packet types (e.g. polls) need support for interactions, to communicate back to sender of a packet (or even to third parties). Receiving updates to certain packets (e.g. read receipts or comments) are valid use cases as well. How this can be done is discussed in sections :ref:`4.2.4. Sending Interactions ` and :ref:`4.2.5. Receiving Updates / Interactions `. 1.1 Introductory Notes ---------------------- The format and schema of packets varies among protocols. To support an iconet fallback presentation (fallback-iframe), embedding applications and fallback iframe developers will however have to support a common set of standardized procedures. What is standardized? - Communication between fallback-iframe and embedding application - Iconet-specific metadata - :ref:`Interpreter Manifests ` (documents about the fallback iframes (i.e. interpreters) used to display or convert a packet) - Communicating interactions between embedding application with fallback-iframes What is not standardized? - What packets look like that are to be presented to the user - *What* is communicated - How packets are transported from network A to B / What transport protocol is used. - *How* the iconet metadata is formatted in a given protocol packet The data objects described here are JSON-LD formatted. If you are not familiar with JSON-LD, think of it as plain JSON with some fancy ``@context`` and ``@type`` fields. They allow the JSON keys to be globally uniquely identifiable. |br| Iconet's JSON-LD ``@context`` namespace is: ``https://ns.iconet-foundation.org#`` .. _required-iconet-meta-data: 2. Required Iconet Data for a Packet ==================================== Say, a client received a foreign packet and cannot provide a presentation natively. However, the packet contains iconet data that the client knows how to deal with. This section describes the required iconet data. Note, that iconet metadata that describes how to interpret a packet is static. This makes it cacheable and reduces the privacy and security attack surface for the actual user-content. The following example shows a representation of how the iconet metadata *could* be contained in a JSON-LD object. It holds minimal amount of data, since only the mandatory interpreter from native to html is given. .. code:: JSON-LD { "@context": "https://ns.iconet-foundation.org#", "@type": "Packet", "actor":"iconet:alice@alicenet.net", "to": "iconet:bob@bobnet.net", "interpreterManifests": [ { "@id": "", "sourceTypes": [""], "targetTypes":[""], "sha512": "" } ], "content": [ { "packetType": "", "payload": "" }, { "packetType": "", "payload": "" } ] } .. note:: It is up to a given protocol, how this metadata is *actually* contained in a packet. XML-based protocol designers may wish to use an XML-based representation over a JSON-based one, for example. When the packet crosses protocol borders however, it needs to be ensured to be formatted in JSON-LD. 2.1 Field Descriptions ---------------------- .. csv-table:: :header: "Field Name", "Type", "Description" :widths: auto " ``@context``", " ``string|object|array``", " The JSON-LD context namespace. This should be set to ``https://ns.iconet-foundation.org#``. You can find more details `here `_. " " ``@type``", " ``string``", " The type of data, the packet contains. For regular payloads, this would be ``Packet``. Depending on the context, the types ``Interaction``, ``TranslatedPacket``, (``Update``, ``UpdateInquiry``) may be applicable.|br| The semantics for those packets are discussed in later sections. " " ``interpreterManifests``", " ``array`` of interpreter manifest descriptions", " An interpreter manifest contains a list of interpreter descriptions. Interpreters take a foreign protocol's packet and either show a presentation or translate the packet to a different format. " " ``interpreterManifests[i] .@id``", " ``string``", " The location of the manifest or a ``data:`` URI containing the interpreter manifest. " " ``interpreterManifests[i] .sourceTypes``", " ``array`` of mime type ``string``", " A list of mime types or custom, application-specific types. |br| For each input type in the list, the manifest must provide an interpreter accepting the given input type. " " ``interpreterManifests[i] .targetTypes``", " ``array`` of mime type ``string``", " A list of mime types or custom, application-specific types. |br| For each target type in the list, the manifest must provide an interpreter producing the given target type. |br| Every packet must be able to find an interpreter with target ``application/iconet+html`` (mime type of fallback presentation-iframe). " " ``interpreterManifests[i] .sha512``", " hex ``string``", " A sha512 hex signature of the interpreter manifest document. Tip: can be computed with ``crypto.subtle.digest('sha512', data)`` in javascript. " " ``content``", " ``array`` of content records.", " Each content record consists of fields that describe and hold the same data but in a different format. If a client does not support the first listed content record, it can go down the list. It is advisable to provide a plain text fallback as last item. " " ``content[i].packetType``", " an extended mime type ``string``", " This field describes the type of the ``payload`` field content. This may be a general type like ``text/plain`` or ``image/jpeg``, or it can be a non-standard application-specific mime type (e.g. application/matrix). " " ``content[i].payload``", " ``string``", " This field contains the data of the packet sent. The type and format is not specified and needs to be interpreted by the application or an interpreter that is linked in the interpreter manifest. |br| An implementing protocol will likely want to allow this field to be be undefined, if the wrapping packet (i.e. the packet that contains this iconet packet) is to be used as payload. " .. _interpreter-manifests: 3. Interpreter Manifests ======================== WIP-Level: 2 The interpreter manifests are JSON-documents that contain the metadata for fallback-iframes and translators. The manifests are linked by iconet-supporting packets and should be cached by the clients. When a client does not know how to present a packet to a user, it will fetch the manifest for a given source packet type and use a fallback presenter- or translator-iframe referenced in the interpreter manifest to present or translate the foreign packet. **The manifest format is standardized**, in comparison to the metadata described in the :ref:`section above (Required Iconet Data for a Packet) `. You can see an example below: .. code:: JSON-LD { "@context": "https://ns.iconet-foundation.org#", "@type": "InterpreterManifest", "@id": "", "interpreters": [ { "@id": "", "sourceType": "<(custom) mime type, e.g. application/activity+json>", "targetType": "<(custom) mime type application/matrix+json or application/iconet+html>", "sha512": "", "permissions": { "": "" } } ] } If the ``targetType`` of a here given interpreter is ``application/iconet+html``, the ``@id`` field must reference a HTML document that is a :ref:`presenter iframe `. |br| If the ``targetType`` of a here given interpreter is anything else, the ``@id`` field must reference a HTML document that is a :ref:`translator iframe ` for that target type. |br| The ``@id`` field may have a ``data:`` URI value containing the HTML payload. |br| Permissions are described in :ref:`4.1.1 Fallback-iframe Permissions `. .. _fallback-iframes: 4. Fallback-iframes =================== Fallback-iframes build the foundation of presenting packets to the user or translating them. The :ref:`interpreter manifest's ` ``targetType`` must reference a fallback iframe HTML document. The HTML document must be embedded and sandboxed using the `HTML iframe tag `_. |br| There are multiple methods described for embedding and sandboxing in section :ref:`4.1.3 Sandboxing Iframes `. This section describes the communication and encapsulation between *embedding application* and *fallback-iframe*. The embedding application passes a packet to the embedded fallback-iframe to display it, see :ref:`4.2 Communication between Embedding Application and Fallback-iframe ` for the walkthrough. There are two types of fallback iframes: Translator Iframes and Presenter Iframes. Translator iframes simply return a packet translated to a different format when they are given a packet, as described in :ref:`4.2.3. Packet Translation Response `. Presenter iframes instead render a HTML presentation. Users may interact with them and the iframes may trigger interaction packets back to the sender of the packet, as described in :ref:`4.2.4. Sending Interactions `. .. seealso:: You can find an example document, an embedding application that embeds an iframe, enforces restrictions, and initiates communication `here <./_static/code-examples/iframe-sandboxing/parent.html>`_. Since by default, fallback-iframes are not allowed to connect to endpoints on the web, all data needs to be embedded within the iframe's HTML. You can see an example of an embedded image `here <./_static/code-examples/iframe-blobs/html-with-image-data.html>`_. To maintain security and safety for users, it is important to sandbox the iframes and restrict permissions. For permissions and sandboxing, see the section linked here: .. toctree:: :titlesonly: :maxdepth: 2 4.1 Iframe Permissions and Sandboxing .. _parent-iframe-communication: 4.2 Communication between Embedding Application and Fallback-iframe ------------------------------------------------------------------- The communication flow to set up the communication looks as follows 1. The fallback-iframe initiates the communication, once loaded. It transfers a message port to the parent. 2. The parent receives the initiation request and responds with the iconet packet to render to the user. 3. For Translators: The iconet translator iframe responds with the translated packet. Communication has finished. 4. Optional: The iconet presenter iframe requests to send away an interaction packet. 5. Optional & at Discussion: The parent receives an additional packet that is passed on to the fallback-iframe. .. _iframe-ready: 4.2.1 Fallback-Iframe Ready ~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the fallback-iframe is ready to receive packets, it calls ``parent.postMessage()`` (see `reference `_) with ``targetOrigin`` of ``*``. The ``message`` parameter must look as follows: .. code:: JSON-LD { "@context": "https://ns.iconet-foundation.org#", "@type": "IframeReady" } The fallback-iframe MUST create a `message channel `_ and pass its `message port `_ using the ``transfer`` parameter of ``parent.postMessage()``. |br| The message channel must be used for all future communication. The initiation in the fallback-iframe may look something like: .. _message-channel-initiation-code: .. code:: javascript document.addEventListener("DOMContentLoaded", async() => { // Create a message channel for the future communication with the parent. const messageChannel = new MessageChannel(); messageChannel.port1.onmessage = (messageEvent) => { console.info("Message received from parent!", messageEvent); // Handle incoming data and render a presentation. }; // Send initial message to parent, transferring the message port. parent.postMessage({ "@context": "https://ns.iconet-foundation.org#", "@type": "IframeReady" }, "*", [messageChannel.port2] ); }); .. _iframe-parent-response: 4.2.2 Parent Response ~~~~~~~~~~~~~~~~~~~~~ The parent, listening to the iframe's ``message`` events, receives the message event and the transferred message port. Using the message port, the parent responds with the packet payload (``event.ports[0].postMessage(packetPayload)``). The listener must validate that the iframe's initial message comes from the expected source iframe. See the code example for an embedding application listening to an iframe: .. code:: javascript window.addEventListener("message", (event) => { // Validate event source. if (event.source !== targetIframe.contentWindow) { // Handle illegal message. return; } // The iframe passed a message port for further and secure communication. iframeMessagePort = event.ports[0]; iframeMessagePort.onMessage = (message) => { // Handle message from iframe here. }; // Pass the received foreign iconet packet payload to the iframe. iframeMessagePort.postMessage(payloadForIframesMimeType); }); The fallback iframe can now use the received payload (which was formatted in the ``sourceType`` specified by the interpreter manifest), to either render a presentation (if the ``targetType`` was ``application/iconet+html``) or translate the packet to the according ``targetType`` otherwise. .. _iframe-packet-translation: 4.2.3. Packet Translation Response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WIP-Level: 2 If the fallback-iframe is a translator iframe and has received the foreign packet, it responds with the translated packet as following: .. code:: JSON-LD { "@context": "https://ns.iconet-foundation.org#", "@type": "TranslatedPacket", "originalPacket": "", "mimetype": "" } .. _iframe-sending-interactions: 4.2.4. Receiving Updates / Sending Interactions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is necessary to receive updates to a packet, e.g. to load the newest version of a post. Since creation of the post and the actual viewing by the recipient interactions and updates may have happened. The updates are requested and interactions are sent by the fallback iframe through native APIs provided by the sending server. In the manifest such native API's need to be listed in allowedSources according to the :ref:`Fallback-iframe Permissions `. Example: .. code:: JSON-LD "allowedSources": [ "http://localhost:8001/api/getPost.php", "http://localhost:8001/api/addComment.php" ] This leverages flexible capabilities for the fallback-iframe developer but may lead to a larger amount of (meta) data leakage to the whitelisted sources. In addition, the whitelisted sources should be approved by the embedding application itself and/or the user which might turn out to be challenging from a UX perspective. 5. Transport =================== So how do the packets reach their supposed destination? There are three ways: .. _native_transport: 5.1 Native Transport ------------------------------------------------------------------- The core use-case of iconet is, to provide a fallback for within networks, where connectivity is already established. In this case decentral applications with already common understandings of actors, relationships do share means of communication and security. It is trivial for them, to also include the required fallback fields into their exchanged packets. Here you see an example of a activitystream packet including the iconet information: .. code:: JSON-LD { "type":"Create", "@context":"https://www.w3.org/ns/activitystreams", "id":"https://bridge.localhost/b3f764ba-6343-419a-be42-a91580b7454b", "actor":"https://bridge.localhost/user/alice__neta.localhost", "object":{ "type":"Note", "https://ns.iconet-foundation.org#iconet":{ "@context":"https://ns.iconet-foundation.org#", "@type":"Packet", "@id":"https://bridge.localhost/9c94ca30-60e0-4951-aef2-e406309b0390", "actor":"alice__neta.localhost@bridge.localhost", "to":[ "admin@localhost:3000" ], "interpreterManifests":[ { "manifestUri":"http://neta.localhost/iconet/formats/markdown/manifest.json", "sourceTypes":[ "text/markdown" ], "targetTypes":[ "application/iconet+html" ], "sha-512":"empty" } ], "content":[ { "packetType":"text/markdown", "payload":"## Title\nText `code`" } ], "XDEBUG_SESSION_START":"13228" }, "@context":"https://www.w3.org/ns/activitystreams", "id":"https://bridge.localhost/4fb30562-6f2e-48f2-9e98-bb59b7f9e049", "published":"2023-02-26T14:21:36+00:00", "content":"This status contains iconet data.", "to":[ "http://localhost:3000/users/admin", "https://www.w3.org/ns/activitystreams#Public" ] } } .. _fallback_transport: 5.2 Fallback Transport -------------------------- For communication between parties on different protocols, the information format, schema, authentication methods, API endpoints, transmission protocol, etc. might not align. Different networks which have the same fallback mechanism established and manage to exchange the fallback information, can provide interconnectivity to their users. That's why it makes also sense, to have a fallback way for transport established. 5.2.1 Adressing & Routing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To send a message, the addressed receiver needs to be uniquely identifiable and locatable. Users need to exchange addresses in URI format. If they do not have a common addressing protocol, they shall use the iconet schema: `iconet:@` - The dereferenceable address is the endpoint the message is sent to. - The domain-specific identifier is only required to be processed by the receiving server. The ``iconet:`` URI scheme specifies the protocol to be used, i.e. makes clear that this is an iconet address. As transport protocol HTTPS is used. As endpoint address we define ``/iconet/``, while in the future a port on the main address should be reserved for fallback transportation. 5.2.2 Encryption & Security ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the sending and receiving party do not share means for encryption and authentication, we recommend a fallback encryption method. We use a :ref:`hybrid cryptosystem ` similiar to PGP for our encryption porpuses. The payload of each packet gets encrypted symmetrically with an AES-Secret. The secret get encrypted with each contacts public key. How each contacts public key is obtained and trusted, needs to be done according to the personal trust model. Here is our example for an encrypted Packet: .. code:: JSON-LD { "@context": "https://ns.iconet-foundation.org#", "@type": "EncryptedPacket", "actor": "bob@netb.localhost", "to": "alice@neta.localhost", "EncryptedSecret": "EncryptedContent": } 5.3 Bridged Transport -------------------------- Bridges are the hybrid solution between each native transport and a universal fallback transport. While there are a couple of downside with bridges, they can be useful in the early adoption phase, when not many servers have adopted the fallback transport yet. This way more users can be reached with interconnectivity. 1. **Where are bridges hosted?** - **Case 1: Every individual user hosts its own bridge.** |br| Bridges are a risk for privacy, since traffic has to be decrypted before it can be bridged (and encrypted again). This issue can be avoided, when users host their own bridges on a trusted device for example on the client. Also, bridging remains easier since the bridge only needs to act as the user on the remote network (puppet bridge). **Downside**: Every user will have to host an own bridge. - **Case 2: Hosting a bridge per room or server.** |br| In this case, users don't need individual bridges. However, all users will have to trust the bridge not to abuse its power to read and manipulate users messages. Additionally, many platforms do not support bridges that operate this way. In the worst-case a bridge bot that joined a room will post a message that describes the sender by appending its name to the message body. 2. **(How) can we discover and reach out to users of different protocols?** |br| Ideally, a user is able to find contacts on different platforms (e.g. by phone number or email address). Therefore, not only a cross-platform user index needs to be present but also an endpoint must be clear which the protocol can target to transfer a message across to a different protocol. The bridging endpoint needs to be added to each users address, so it can be forwarded from here. E.g.: `alice@netA.org@bridge.net` There are different types of bridges to transfer packets across platforms. `This matrix post `_ discusses different types of bridges for the interested reader.