Skip to content

feat(bots): 🐣 Start with implementing bots#9458

Merged
nickvergessen merged 16 commits intomasterfrom
feat/1879/webhooks
Aug 7, 2023
Merged

feat(bots): 🐣 Start with implementing bots#9458
nickvergessen merged 16 commits intomasterfrom
feat/1879/webhooks

Conversation

@nickvergessen
Copy link
Member

@nickvergessen nickvergessen commented May 4, 2023

☑️ Resolves

Config (webhook.json)

{
	"secret": "At least 32 long random shared secret"
}

Receiver (webhook.php)

<?php

$configData = file_get_contents('./webhook.json');

if ($configData === false) {
	file_put_contents('./webhook.log', "[ERROR] Could not read config]\n", FILE_APPEND);
	return;
}

$config = json_decode($configData, true);

if ($config === null) {
	file_put_contents('./webhook.log', "[ERROR] Could not json_decode config\n", FILE_APPEND);
	return;
}

$signature = $_SERVER['HTTP_X_NEXTCLOUD_TALK_SIGNATURE'] ?? '';
$random = $_SERVER['HTTP_X_NEXTCLOUD_TALK_RANDOM'] ?? '';
$server = $_SERVER['HTTP_X_NEXTCLOUD_TALK_BACKEND'] ?? '';

$body = file_get_contents('php://input');
$generatedDigest = hash_hmac('sha256', $random . $body, $config['secret']);

if (!hash_equals($generatedDigest, strtolower($signature))) {
	file_put_contents('./webhook.log', "[ERROR] Message signature could not be verified\n", FILE_APPEND);
	return;
}

file_put_contents('./webhook.log', $body . "\n", FILE_APPEND);
$data = json_decode($body, true);

if ($data['type'] === 'Create') {
	file_put_contents('./webhook.log', '[OK]    ' . $data['object']['name'] . "\n", FILE_APPEND);
}

if ($config['server']) {
	$message = 'Re: ' . json_decode($data['object']['name'], true)['message'];
	$body = [
		'message' => $message,
		'referenceId' => sha1($random),
		'replyTo' => (int) $data['object']['id'],
	];

	$jsonBody = json_encode($body, JSON_THROW_ON_ERROR);

	$random = bin2hex(random_bytes(32));
	$hash = hash_hmac('sha256', $random . $message, $config['secret']);
	file_put_contents('./webhook.log', '[INFO]  Reply: Random ' . $random . "\n", FILE_APPEND);
	file_put_contents('./webhook.log', '[INFO]  Reply: Hash ' . $hash . "\n", FILE_APPEND);

	try {
		$ch = curl_init(rtrim($server, '/') . '/ocs/v2.php/apps/spreed/api/v1/bot/' . $data['target']['id'] . '/message');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonBody);
		curl_setopt($ch, CURLOPT_USERAGENT, 'nextcloud-talk-bot/1.0');
		curl_setopt($ch, CURLOPT_HTTPHEADER, [
			'OCS-APIRequest: true',
			'Content-Type: application/json',
			'X-Nextcloud-Talk-Bot-Random: ' . $random,
			'X-Nextcloud-Talk-Bot-Signature: ' . $hash,
		]);
		$content  = curl_exec($ch);

		$error = curl_error($ch);
		if ($error) {
			file_put_contents('./webhook.log', '[ERROR] CURL error: ' . $error . "\n", FILE_APPEND);
		} elseif ($content) {
			file_put_contents('./webhook.log', '[INFO]  CURL response: ' . $content . "\n", FILE_APPEND);
		}

		curl_close($ch);
	} catch (\Exception $exception) {
		file_put_contents('./webhook.log', '[ERROR] ' . get_class($exception) . ': ' . $exception->getMessage() . "\n", FILE_APPEND);
	}
}

Webhook message received

{
  "type": "Create",
  "actor": {
    "type": "Person",
    "id": "users/admin",
    "name": "Laura Adams"
  },
  "object": {
    "type": "Note",
    "id": "2370",
    "name": "{\"message\":\"Hello {mention-call1} \\ud83d\\udc4b\",\"parameters\":{\"mention-call1\":{\"type\":\"call\",\"id\":\"u48mn5p4\",\"name\":\"Webhooked room\",\"call-type\":\"group\",\"icon-url\":\"https:\\/\\/192.168.2.63\\/ocs\\/v2.php\\/apps\\/spreed\\/api\\/v1\\/room\\/u48mn5p4\\/avatar?v=996f0d79\"}}}"
  },
  "target": {
    "type": "Collection",
    "id": "u48mn5p4",
    "name": "Webhooked room"
  }
}

@nickvergessen nickvergessen added 2. developing feature: integration 📦 Integration with 3rd party (chat) service labels May 4, 2023
@nickvergessen nickvergessen added this to the 💜 Next Major (28) milestone May 4, 2023
@nickvergessen nickvergessen self-assigned this May 4, 2023
@nickvergessen nickvergessen marked this pull request as draft May 4, 2023 21:50
@nickvergessen

This comment was marked as resolved.

@nickvergessen nickvergessen added feature: api 🛠️ OCS API for conversations, chats and participants feature: bots 🤖 /commands in chat messages labels Jun 2, 2023
@nickvergessen nickvergessen changed the title feat(webhooks): Start with implementing webhooks for chat messages feat(webhooks): Start with implementing bots Jul 10, 2023
@nickvergessen nickvergessen changed the title feat(webhooks): Start with implementing bots feat(bots): Start with implementing bots Jul 10, 2023
@nickvergessen nickvergessen changed the title feat(bots): Start with implementing bots feat(bots): 🐣 Start with implementing bots Jul 21, 2023
@nickvergessen
Copy link
Member Author

nickvergessen commented Jul 21, 2023

Next steps

  • Add commands to handle bots
    • List
    • Install
      • Setup
      • Remove
    • Uninstall
  • States
    • Enable
    • Disable
    • Prevent installing to new conversations
  • API for moderators to see all bots (that are setupable) and enable/disable for current conversation

@nickvergessen nickvergessen force-pushed the feat/1879/webhooks branch 2 times, most recently from dd69534 to 1bdc64d Compare July 27, 2023 06:51
@nickvergessen nickvergessen force-pushed the feat/1879/webhooks branch 2 times, most recently from dff4f01 to 7c5ee81 Compare August 2, 2023 18:47
@nickvergessen
Copy link
Member Author

Now with integration tests for setup/remove as moderator as well as handling all cases via OCC.

Rendering on iOS and Android also looks good:

iOS Android
photo_2023-08-02_20-54-24 photo_2023-08-02_20-51-42

So I guess API is ready to review.

@nickvergessen
Copy link
Member Author

Tests now fail due to missing #10078

Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
… endpoint

Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
@nickvergessen nickvergessen enabled auto-merge August 7, 2023 10:49
@nickvergessen nickvergessen merged commit e68fe37 into master Aug 7, 2023
@nickvergessen nickvergessen deleted the feat/1879/webhooks branch August 7, 2023 11:41
@nickvergessen nickvergessen restored the feat/1879/webhooks branch August 7, 2023 13:48
@nickvergessen nickvergessen deleted the feat/1879/webhooks branch August 24, 2023 14:34
@mkrecek234
Copy link

@nickvergessen Thanks a lot for implementing webhooks. Unfortunately I struggle to accomplish the following which was also requested in issue #1879 - Slack and most other chat solutions allow the user to easily create a token for a chat room, and based on that token create a webhook secure URL which then can be used to let any other application send a message into that chat room (no authentication then required). How can I accomplish this now programmatically? I want users to add any room to my own (non-Nextcloud) app, and let my app communicate via Nextcloud Talk to users. Thank you for a hint.

@nickvergessen
Copy link
Member Author

Responded in the issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: api 🛠️ OCS API for conversations, chats and participants feature: bots 🤖 /commands in chat messages feature: integration 📦 Integration with 3rd party (chat) service

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants