From bdb25d1437ffa83c58daab898d12b9cfe17226d4 Mon Sep 17 00:00:00 2001 From: Eric Doughty-Papassideris Date: Wed, 12 Jun 2024 14:15:07 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Documented=20plugin=20configurat?= =?UTF-8?q?ion=20(#547)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Documentation/docs/plugins.md | 145 +++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 65 deletions(-) diff --git a/Documentation/docs/plugins.md b/Documentation/docs/plugins.md index f37e3027..ba83a027 100644 --- a/Documentation/docs/plugins.md +++ b/Documentation/docs/plugins.md @@ -1,6 +1,27 @@ # Twake Drive - How to enable plugins -## Edit the /backend/node/config/{env}.json file to add the plugin, here is an example with onlyoffice: +Plugins, or applications, are configured in the backend's json configuration file `/backend/node/config/{env}.json`: + +```json +{ + "applications": { + "grid": [ ], + "plugins": [ ] + } +} +``` + +The environment variable `APPLICATIONS` can be used to override the configuration file, eg: + +```sh +APPLICATIONS='{ "grid": [ ... ], "plugins": [ ... ] }' +``` + +*Note: the `applications` key is the root of the environment variable's json.* + +## Application grid entries + +Links in top right drop down application grid can be configured in the `applications.grid` array, eg: ```json { @@ -11,15 +32,56 @@ "logo": "/public/img/grid/tmail.png", "url": "https://tmail.linagora.com/" } - ], + ] + } +} +``` + +## Plugins + +*Currently all applications are automatically active for all companies (subject to change).* + +Plugins are defined as entries under the `applications.plugins` array, with at least the following properties: + +- `id` is mandatory and must be unique to each plugin +- `internal_domain` is the internal domain of the plugin's server, it must be the same as the one in the docker-compose.yml file for ex. or resolvable and accessible to the Twake Drive backend server. +- `external_prefix` is the external URL prefix of the plugin exposed by the backend and proxied to the `internal_domain`. +- `api.private_key` is the shared secret used by the plugin's server to authentify to the backend + +### Proxying + +- The frontend server in development (next), or nginx in production, should relay all requests to `/plugins/*` to the same url on the Twake Drive backend +- The Twake Drive backend will proxy all requests below `external_prefix` to the same url at `internal_domain` intead for the matching plugin + +### Application authentification + +- To send API commands to Twake Drive, the application must first obtain a JWT token. This is obtained by `POST https://[backend]/api/console/v1/login`, with a JSON body containing the shared `{ id, secret: api.private_key }`, and an `Authorization` header with as Basic auth the base64 encoded pair in the format `id:api.private_key`. See [refreshToken](https://github.com/linagora/twake-drive/blob/main/tdrive/connectors/onlyoffice-connector/src/services/api.service.ts). The response should be in the format `{resource: {access_token: { value }}}`. The resulting token expires and should be periodically renewed. + +- To authenticate further API requests, add the returned token to the headers as `Authorization: Bearer $token`. + +### User initiated notifications to a plugin + +`POST /companies/:company_id/applications/:app_id/event` + +Sending a request of this format to the backend will proxy that request after signing it to `plugin.api.hooks_url`. Accepts JSON body with fields `type`, `content` and optionally `name`. Adds the header `X-Tdrive-Signature` containing a hex encoded sha256 of the json body hmac signature with `plugin.api.private_key`, and returns the remote's response to the user. + +The payload sent to the hooks server includes: `{ type, name, content, connection_id, user_id, company_id, workspace_id}` (see `ApplicationHooksService.notifyApp`). + +## File plugins + +The configuration in `plugin.display.tdrive.files` allows a plugin to hook file creation, preview and edition. + +Here is (an incomplete) example based of the Only Office connector plugin. + +```json +{ + "applications": { "plugins": [ { "id": "tdrive_onlyoffice", "internal_domain": "http://plugins_onlyoffice:5000/", "external_prefix": "/plugins/onlyoffice/", - "api": { - "private_key": "apisecret" - }, + "api": { "private_key": "apisecret" }, "display": { "tdrive": { "version": 1, @@ -32,32 +94,9 @@ "url": "/plugins/onlyoffice/assets/empty.docx", "filename": "Untitled.docx", "name": "ONLYOFFICE Word Document" - }, - { - "url": "/plugins/onlyoffice/assets/empty.xlsx", - "filename": "Untitled.xlsx", - "name": "ONLYOFFICE Excel Document" - }, - { - "url": "/plugins/onlyoffice/assets/empty.pptx", - "filename": "Untitled.pptx", - "name": "ONLYOFFICE PowerPoint Document" } ], - "extensions": [ - "xlsx", - "pptx", - "docx", - "xls", - "ppt", - "doc", - "odt", - "ods", - "odp", - "txt", - "html", - "csv" - ] + "extensions": [ "docx", "odt" ] } } } @@ -77,47 +116,23 @@ } ``` -#### Explanation +### Creation -- `grid` is the list of applications that will be displayed in the grid on top bar, here an example with tmail -- `plugins` is the list of plugins for tdrive, here an example with onlyoffice. -- `plugins.id` is mandatory and must be unique to each plusing -- `plugins.internal_domain` (only if installed inside the same docker and same domain) is the internal domain of the plugin, it must be the same as the one in the docker-compose.yml file -- `plugins.external_prefix` (only if installed outside of the docker) is the external prefix of the plugin. When the frontend will call https://tdrive.app/plugins/onlyoffice/ it will be redirected to the internal_domain. -- **If your server and frontend runs on different urls** then you must replace all the /plugins[...] by http://my_server_url/plugins[...] except for the external_prefix URI. +The field `editor.empty_files` can contain a list of template empty files editable by this plugin. The files must be hosted below the url in `external_prefix` (eg. `"/plugins/onlyoffice/"`). The backend will proxy all requests below `external_prefix` to the same url at `internal_domain` intead. -#### You can also set it using env variables +The file will then be downloaded by the browser from that URL, added to the current folder by Twake Drive, and opened in the provided editor. -``` -APPLICATIONS='{ "grid": [ { "name": "Tmail", "logo": "/public/img/grid/tmail.png", "url": "https://tmail.linagora.com/" } ], "plugins": [ { "id": "tdrive_onlyoffice", "internal_domain": "http://plugins_onlyoffice:5000/", "external_prefix": "/plugins/onlyoffice/", "api": { "private_key": "apisecret" }, "display": { "tdrive": { "version": 1, "files": { "editor": { "preview_url": "/plugins/onlyoffice/?preview=1", "edition_url": "/plugins/onlyoffice/", "empty_files": [ { "url": "/plugins/onlyoffice/assets/empty.docx", "filename": "Untitled.docx", "name": "ONLYOFFICE Word Document" }, { "url": "/plugins/onlyoffice/assets/empty.xlsx", "filename": "Untitled.xlsx", "name": "ONLYOFFICE Excel Document" }, { "url": "/plugins/onlyoffice/assets/empty.pptx", "filename": "Untitled.pptx", "name": "ONLYOFFICE PowerPoint Document" } ], "extensions": [ "xlsx", "pptx", "docx", "xls", "ppt", "doc", "odt", "ods", "odp", "txt", "html", "csv" ] } } } }, "identity": { "code": "only_office", "name": "Only Office", "icon": "/plugins/onlyoffice/assets/logo.png", "description": null, "website": "http://twake.app/", "categories": [], "compatibility": ["tdrive"] } } ] }' -``` +### Preview and Editing -## Add and run the docker container for the plugin +When a user requests a preview and then possibly to edit the file, an IFrame is opened and pointed to `files.editor.preview_url` or `files.editor.edition_url`, with the following query parameters: -For instance with onlyoffice, you can find the plugin here: https://github.com/linagora/Twake-Plugin-Onlyoffice + - `token`: a JWT that can be used to authenticate as the user when calling the Twake Drive API + - `workspace_id`, `company_id`: Identifiers of the respective items + - `file_id`: External file identifier + - `drive_file_id`: Optional internal (to Twake Drive) file identifier -In the docker-compose.yml you can add the following: +In the case of the OnlyOffice application, these URLs are pointing to the connector plugin, which then proxies back and forth with the OnlyOffice document server. -```yaml -plugins_onlyoffice: - image: onlyoffice-connector - restart: unless-stopped - environment: - - SERVER_PORT=5000 - - SERVER_PREFIX=/plugins/onlyoffice/ - - CREDENTIALS_ENDPOINT=http://node/ - - ONLY_OFFICE_SERVER=https://onlyoffice.server.come/ - - CREDENTIALS_ID=tdrive_onlyoffice - - CREDENTIALS_SECRET=apisecret -``` +### Example: OnlyOffice plugin -Note: - -- Make sure the network is shared with node -- Make sure the service name matches the internal_domain in the config file - -## Run everything - -When starting the docker-compose, the plugin will be available on https://[frontend]/plugins/onlyoffice/ you can test everything works by opening the url https://[frontend]/plugins/onlyoffice/assets/logo.png . - -If the logo displays, then open Twake Drive, and see if you can create a new OnlyOffice Spreadsheet when clicking on "New". +The [OnlyOffice connector plugin](https://github.com/linagora/twake-drive/tree/main/tdrive/connectors/onlyoffice-connector) is an example of plugin. It's readme includes an example configuration for the backend.