Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 16 commits into from
Aug 7, 2023
Merged

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
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

lib/Chat/ChatManager.php Outdated Show resolved Hide resolved
lib/Model/BotConversation.php Outdated Show resolved Hide resolved
lib/Model/BotServer.php Outdated Show resolved Hide resolved
tests/psalm-baseline.xml Show resolved Hide resolved
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 merged commit e68fe37 into master Aug 7, 2023
30 checks passed
@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
3. to review 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