From 732d9fb1cc4cd9c92239057cc63c764e449e1177 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 8 Aug 2023 23:14:02 +0200 Subject: feat: Document bots Signed-off-by: Joas Schilling --- docs/bot-management.md | 84 +++++++++++++++ docs/bots.md | 171 ++++++++++++++++++++++++++++++ docs/capabilities.md | 1 + docs/commands.md | 6 ++ docs/constants.md | 7 ++ mkdocs.yml | 4 +- src/components/AdminSettings/Commands.vue | 2 +- 7 files changed, 273 insertions(+), 2 deletions(-) create mode 100644 docs/bot-management.md create mode 100644 docs/bots.md diff --git a/docs/bot-management.md b/docs/bot-management.md new file mode 100644 index 000000000..301f8ba61 --- /dev/null +++ b/docs/bot-management.md @@ -0,0 +1,84 @@ +# Setup and management bots + +Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`: (requires the `bots-v1` capability - available since Nextcloud 27.1) + +## Get list of bots installed on the server + +Lists the bots that are enabled and can be enabled for the conversation + +* Required capability: `bots-v1` +* Method: `GET` +* Endpoint: `bot/admin` + +* Response: + - Status code: + + `200 OK` + + `403 Forbidden` When the current user is not a moderator/owner + + `404 Not Found` When the conversation could not be found for the participant + - Data: + List of bots, each bot has at least: + +| field | type | Description | +|----------------------|--------|----------------------------------------------------------------------------------------------| +| `id` | int | Unique numeric identifier of the bot on this server | +| `name` | string | Display name of the bot shown as author when it posts a message or reaction | +| `description` | string | A longer description of the bot helping moderators to decide if they want to enable this bot | +| `url` | string | URL endpoint that is triggered by this bot | +| `url_hash` | string | Hash of the URL prefixed with `bot-` serves as `actor_id` | +| `state` | int | One of the [Bot states](constants.md#bot-states) | +| `error_count` | int | Number of consecutive errors | +| `last_error_date` | int | UNIX timestamp of the last error | +| `last_error_message` | string | The last exception message or error response information when trying to reach the bot. | + +## Get list of bots for a conversation + +Lists the bots that are enabled and can be enabled for the conversation + +* Required capability: `bots-v1` +* Method: `GET` +* Endpoint: `bot/{token}` + +* Response: + - Status code: + + `200 OK` + + `403 Forbidden` When the current user is not a moderator/owner + + `404 Not Found` When the conversation could not be found for the participant + - Data: + List of bots, each bot has at least: + +| field | type | Description | +|-----------------------|--------|----------------------------------------------------------------------------------------------| +| `id` | int | Unique numeric identifier of the bot on this server | +| `name` | string | Display name of the bot shown as author when it posts a message or reaction | +| `description` | string | A longer description of the bot helping moderators to decide if they want to enable this bot | +| `state` | int | One of the [Bot states](constants.md#bot-states) | + +## Enable a bot for a conversation as a moderator + +* Required capability: `bots-v1` +* Method: `POST` +* Endpoint: `bot/{token}/{botId}` + +* Response: + - Status code: + + `200 OK` When the bot is already enabled in the conversation + + `201 Created` When the bot is now enabled in the conversation + + `400 Bad Request` When the bot ID is unknown on the server + + `400 Bad Request` When the bot is disabled or set to "no-setup" on the server + + `403 Forbidden` When the current user is not a moderator/owner + + `404 Not Found` When the conversation could not be found for the participant + +## Disable a bot for a conversation as a moderator + +* Required capability: `bots-v1` +* Method: `DELETE` +* Endpoint: `bot/{token}/{botId}` + +* Response: + - Status code: + + `200 OK` When the bot is already enabled in the conversation + + `201 Created` When the bot is now enabled in the conversation + + `400 Bad Request` When the bot ID is unknown on the server + + `400 Bad Request` When the bot is disabled or set to "no-setup" on the server + + `403 Forbidden` When the current user is not a moderator/owner + + `404 Not Found` When the conversation could not be found for the participant diff --git a/docs/bots.md b/docs/bots.md new file mode 100644 index 000000000..573d99968 --- /dev/null +++ b/docs/bots.md @@ -0,0 +1,171 @@ +# Bots and Webhooks + +Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`: (requires the `bots-v1` capability - available since Nextcloud 27.1) + +Webhook based bots are available with the Nextcloud 27.1 compatible Nextcloud Talk 17.1 release as a first version + +!!! note + + For security reasons bots can only be added via the + command line. `./occ talk:bot:install --help` gives you + a short overview of the required arguments, but they are + also explained in the [OCC documentation](occ.md#talkbotinstall). + +--- + +## Receiving chat messages + +Messages are signed using the shared secret that is specified when installing a bot on the server. +Create a HMAC with SHA256 over the request body and the `RANDOM` header using the shared secret. +Only when the `SIGNATURE` matches the request should be accepted and handled. + +**Sample PHP code:** + +```php +$digest = hash_hmac('sha256', $_SERVER['HTTP_X_NEXTCLOUD_TALK_RANDOM'] . file_get_contents('php://input'), $secret); + +if (!hash_equals($digest, strtolower($_SERVER['HTTP_X_NEXTCLOUD_TALK_SIGNATURE']))) { + exit; +} +``` + +### Headers + +| Header | Content type | Description | +|-----------------------------------|---------------------|------------------------------------------------------| +| `HTTP_X_NEXTCLOUD_TALK_SIGNATURE` | `[a-f0-9]{64}` | SHA265 signature of the body | +| `HTTP_X_NEXTCLOUD_TALK_RANDOM` | `[A-Za-z0-9+\]{64}` | Random string used when signing the body | +| `HTTP_X_NEXTCLOUD_TALK_BACKEND` | URI | Base URL of the Nextcloud server sending the message | + +### Content + +The content format follows the [ActivityPub](https://www.w3.org/TR/activitypub/) dictionary. + +#### Sample chat message + +```json +{ + "type": "Create", + "actor": { + "type": "Person", + "id": "users/ada-lovelace", + "name": "Ada Lovelace" + }, + "object": { + "type": "Note", + "id": "1567", + "name": "message", + "content": "{\"message\":\"hi {mention-call1} !\",\"parameters\":{\"mention-call1\":{\"type\":\"call\",\"id\":\"n3xtc10ud\",\"name\":\"world\",\"call-type\":\"group\",\"icon-url\":\"https:\\/\\/nextcloud.local\\/ocs\\/v2.php\\/apps\\/spreed\\/api\\/v1\\/room\\/n3xtc10ud\\/avatar\"}}}", + "mediaType": "text/markdown" + }, + "target": { + "type": "Collection", + "id": "n3xtc10ud", + "name": "world" + } +} +``` + +#### Explanation + +| Path | Description | +|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| actor.id | One of the known [attendee types](constants.md#attendee-types) followed by the `/` slash character and a unique identifier within the given type. For users it is the Nextcloud user ID, for guests a sha1 value. | +| actor.name | The display name of the attendee sending the message. | +| object.id | The message ID of the given message on the origin server. It can be used to react or reply to the given message. | +| object.name | For normal written messages `message`, otherwise one of the known [system message identifiers](chat.md#system-messages). | +| object.content | A JSON encoded dictionary with a `message` and `parameters` key. The message can include placeholders and the [Rich Object parameters](https://github.com/nextcloud/server/blob/master/lib/public/RichObjectStrings/Definitions.php) are rendered into it in the chat view. | +| object.mediaType | `text/markdown` when the message should be interpreted as Markdown. Otherwise `text/plain`. | +| target.id | The token of the conversation in which the message was posted. It can be used to react or reply to the given message. | +| target.name | The name of the conversation in which the message was posted. | + +## Sending a chat message + +Bots can also send message. On the sending process the same signature/verification method is applied. + +* Required capability: `bots-v1` +* Method: `POST` +* Endpoint: `/bot/{token}/message` +* Header: + +| Name | Description | +|----------------------------------|-----------------------------------------------------------------| +| `X-Nextcloud-Talk-Bot-Random` | The random value used when signing the request | +| `X-Nextcloud-Talk-Bot-Signature` | The signature to validate the request comes from an enabled bot | +| `OCS-APIRequest` | Needs to be set to `true` to access the ocs/vX.php endpoint | + +* Data: + +| field | type | Description | +|--------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| `message` | string | The message the user wants to say | +| `replyTo` | int | The message ID this message is a reply to (only allowed for messages from the same conversation and when the message type is not `system` or `command`) | +| `referenceId` | string | A reference string to be able to identify the message again in a "get messages" request, should be a random sha256 | +| `silent` | bool | If sent silent the message will not create chat notifications even for users | + +* Response: + - Status code: + + `201 Created` When the message was posted successfully + + `400 Bad Request` When the provided replyTo parameter is invalid + + `401 Unauthenticated` When the bot could not be verified for the conversation + + `404 Not Found` When the conversation could not be found + + `413 Payload Too Large` When the message was longer than the allowed limit of 32000 characters (or 1000 until Nextcloud 16.0.1, check the `spreed => config => chat => max-length` capability for the limit) + + `429 Too Many Requests` When `401 Unauthenticated` was triggered too often + +## Reacting to a chat message + +Bots can also react to a message. The same signature/verification method is applied. + +* Required capability: `bots-v1` +* Method: `POST` +* Endpoint: `/bot/{token}/reaction/{messageId}` +* Header: + +| Name | Description | +|----------------------------------|-----------------------------------------------------------------| +| `X-Nextcloud-Talk-Bot-Random` | The random value used when signing the request | +| `X-Nextcloud-Talk-Bot-Signature` | The signature to validate the request comes from an enabled bot | +| `OCS-APIRequest` | Needs to be set to `true` to access the ocs/vX.php endpoint | + +* Data: + +| field | type | Description | +|------------|--------|----------------| +| `reaction` | string | A single emoji | + +* Response: + - Status code: + + `201 Created` When the reaction was created successfully + + `400 Bad Request` When the provided emoji was invalid + + `401 Unauthenticated` When the bot could not be verified for the conversation + + `404 Not Found` When the conversation or message could not be found + + `429 Too Many Requests` When `401 Unauthenticated` was triggered too often + +## Delete a reaction + +Bots can also remove their previous reaction from amessage. The same signature/verification method is applied. + +* Required capability: `bots-v1` +* Method: `DELETE` +* Endpoint: `/bot/{token}/reaction/{messageId}` +* Header: + +| Name | Description | +|----------------------------------|-----------------------------------------------------------------| +| `X-Nextcloud-Talk-Bot-Random` | The random value used when signing the request | +| `X-Nextcloud-Talk-Bot-Signature` | The signature to validate the request comes from an enabled bot | +| `OCS-APIRequest` | Needs to be set to `true` to access the ocs/vX.php endpoint | + +* Data: + +| field | type | Description | +|------------|--------|----------------| +| `reaction` | string | A single emoji | + +* Response: + - Status code: + + `200 OK` When the reaction was deleted successfully + + `400 Bad Request` When the provided emoji was invalid + + `401 Unauthenticated` When the bot could not be verified for the conversation + + `404 Not Found` When the conversation or message could not be found + + `429 Too Many Requests` When `401 Unauthenticated` was triggered too often diff --git a/docs/capabilities.md b/docs/capabilities.md index 3922b54d5..2fb160374 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -124,3 +124,4 @@ ## 17.1 * `remind-me-later` - Support for "Remind me later" for chat messages exists +* `bots-v1` - Support of the first version for Bots and Webhooks is available diff --git a/docs/commands.md b/docs/commands.md index 3aca4e063..629abb682 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,5 +1,11 @@ # Chat commands +!!! warning + + **Deprecation:** Commands are deprecated in favor of [Bots](bots.md). + +--- + !!! note For security reasons commands can only be added via the diff --git a/docs/constants.md b/docs/constants.md index 729fa33fb..b46977036 100644 --- a/docs/constants.md +++ b/docs/constants.md @@ -147,6 +147,13 @@ * `0` - Public: Participants can see the result immediately and also who voted for which option * `1` - Hidden: The result is hidden until the poll is closed and then only the number of votes for each option are displayed +## Bots + +### Bot states +* `0` Disabled +* `1` Enabled +* `2` No setup - The bot can neither be enabled nor disabled by a moderator + ## Signaling modes * `internal` - No external signaling server is used * `external` - A single external signaling server is used diff --git a/mkdocs.yml b/mkdocs.yml index 31f29074e..0c735564b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,9 +23,10 @@ nav: - 'Server system requirements': 'system-requirements.md' - 'Configuring coTURN': 'TURN.md' - 'Occ commands': 'occ.md' - - 'Commands': 'commands.md' + - 'Commands (deprecated)': 'commands.md' - 'Matterbridge integration': 'matterbridge.md' - 'Developer documentation': + - 'Bots and webhooks': 'bots.md' - 'Constants': 'constants.md' - 'Capabilities': 'capabilities.md' - 'PHP events': 'events.md' @@ -39,6 +40,7 @@ nav: - 'Reaction management': 'reaction.md' - 'Poll management': 'poll.md' - 'Breakout rooms management': 'breakout-rooms.md' + - 'Bots management': 'bot-management.md' - 'Webinar management': 'webinar.md' - 'Settings': 'settings.md' - 'Integration by other apps': 'integration.md' diff --git a/src/components/AdminSettings/Commands.vue b/src/components/AdminSettings/Commands.vue index dd4167d67..71ac59fe6 100644 --- a/src/components/AdminSettings/Commands.vue +++ b/src/components/AdminSettings/Commands.vue @@ -24,7 +24,7 @@

{{ t('spreed', 'Commands') }} - {{ t('spreed', 'Beta') }} + {{ t('spreed', 'Deprecated') }}

-- cgit v1.2.3