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

Webhook Support / bot integration #1879

Closed
4 tasks done
fti7 opened this issue Jun 3, 2019 · 33 comments
Closed
4 tasks done

Webhook Support / bot integration #1879

fti7 opened this issue Jun 3, 2019 · 33 comments

Comments

@fti7
Copy link

fti7 commented Jun 3, 2019

Is your feature request related to a problem? Please describe.
I would like to integrate my Smarthome System into Nextcloud Talk Chat for Notifications etc.

Describe the solution you'd like
Webhook Implementation (Similiar like these on Rocket.Chat/Slack etc)
Webhooks usually per Channel and multiple ones can be added for various integrations

Incoming Webhooks:
Generates an Webhook Token/Credentials to use in Scripts/Tools.
This will allow to send Messages to an specific Channel with an simple API Call. But not to read any messages for Security Reasons.

Outgoing Webhooks:
Send new Messages to an specific URL. (Standardized Format)
Optionally only if the text includes an "trigger word"

Describe alternatives you've considered
Currently im using an Dummy User and fake an normal "Web Client" to send Messages to an Channel. This basically works, but this User can also read Messages (Security Issue).


@nickvergessen nickvergessen added feature: chat 💬 Chat and system messages feature: bots 🤖 /commands in chat messages and removed 0. Needs triage labels Jun 20, 2019
@nickvergessen nickvergessen added this to the 💔 Backlog milestone Jun 20, 2019
@fti7 fti7 mentioned this issue Jul 4, 2019
@BRadHoc
Copy link

BRadHoc commented Jul 4, 2019

Having a go at implementing this, will let you know how I get on

image

@mar565
Copy link

mar565 commented Aug 13, 2019

Can you show us how you did the dummy User solution?

@fti7
Copy link
Author

fti7 commented Aug 16, 2019

@mar565
Basically it does the same as the Browser.

  • Create an Dummy Nextcloud User
  • Create an Channel an get the Channel ID from the URL
<?

function NextcloudTalk_SendMessage($channel_id, $message) {

    $SERVER = "https://XYZ";
    $USER = "notify1";
    $PASS = "notify1pw";

    // notify hack
    $data = array(
                "token" => $channel_id,
                "message" => $message,
                "actorDisplayName" => "PYTHON-NOTIFICATION",
                "actorType" => "",
                "actorId" => "",
                "timestamp" => 0,
                "messageParameters" => array()
    );
    
    $payload = json_encode($data);

    $ch = curl_init($SERVER . '/ocs/v2.php/apps/spreed/api/v1/chat/' . $channel_id);

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($ch, CURLOPT_USERPWD, "$USER:$PASS");
    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

    // Set HTTP Header
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($payload),
        'Accept: application/json',
        'OCS-APIRequest: true')
    );
    
    $result = curl_exec($ch);
    curl_close($ch);

}

NextcloudTalk_SendMessage('jatdu2cc', 'Hello From SYMCON');

?>

@q-wertz
Copy link

q-wertz commented Oct 15, 2019

Having a go at implementing this, will let you know how I get on

@BRadHoc
any news on this?

@loxK
Copy link

loxK commented Oct 24, 2019

Could help. Here is how rocket chat handles webhooks. https://rocket.chat/docs/administrator-guides/integrations/gitlab/

@BRadHoc
Copy link

BRadHoc commented Jan 6, 2020

Appologies for the long delay on this, I've had a lot of stuff going on with work and personal life.

I used a different approach to @fti7 in that I copied the functonality of the Update conversation to create a new window and the same process for putting messages into it.

It's spread across a few files, so not the simplest of solutions.

Also I believe nextcloud flow coming in server v18 will be able to cover this functionality?

@David-Development
Copy link
Member

If anyone is interested in @fti7 solution converted to python3, here you go:

  • Create an Dummy Nextcloud User
  • Create an Channel an get the Channel ID from the URL (in the browser)
import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

However it would still be nice to have some official documentation about this or some official endpoint.

@Window-Hero
Copy link

Hey, any updates on this feature, or any similar features to do with NextCloud Talk? As of now, it seems to only be possible to have automated messages sent as a result of things that occur within NextCloud, seemingly only file changes at the moment, while the original request (as well as my own interest) is about integrating an external system with NextCloud Talk, which is functionality not currently covered by Flows.

@Lulalaby
Copy link

Lulalaby commented Aug 3, 2020

If anyone is interested in @fti7 solution converted to python3, here you go:

  • Create an Dummy Nextcloud User
  • Create an Channel an get the Channel ID from the URL (in the browser)
import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

However it would still be nice to have some official documentation about this or some official endpoint.

Is this working atm?

@nickvergessen
Copy link
Member

Yes, long polling or regularly pinging the api works, but it's still on our todo to implement this properly

@Lulalaby
Copy link

Yes, long polling or regularly pinging the api works, but it's still on our todo to implement this properly

Thanks for the update about this. I'm looking forward!

@niklasgrewe
Copy link

If anyone is interested in @fti7 solution converted to python3, here you go:

  • Create an Dummy Nextcloud User
  • Create an Channel an get the Channel ID from the URL (in the browser)
import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

However it would still be nice to have some official documentation about this or some official endpoint.

possible to convert this to curl, so i can use it in bash scripts like this?

#!/usr/bin/env bash
function usage {
    programName=$0
    echo "description: use this program to post messages to Rocket.chat channel"
    echo "usage: $programName [-b \"message body\"] [-u \"rocket.chat url\"]"
    echo "      -b    The message body"
    echo "      -u    The rocket.chat hook url to post to"
    exit 1
}
while getopts ":b:u:h" opt; do
  case ${opt} in
    u) rocketUrl="$OPTARG"
    ;;
    b) msgBody="$OPTARG"
    ;;
    h) usage
    ;;
    \?) echo "Invalid option -$OPTARG" >&2
    ;;
  esac
done
if [[ ! "${rocketUrl}" || ! "${msgBody}" ]]; then
    echo "all arguments are required"
    usage
fi
read -d '' payLoad << EOF
{"text": "${msgBody}"}
EOF
echo $payLoad
statusCode=$(curl \
        --write-out %{http_code} \
        --silent \
        --output /dev/null \
        -X POST \
        -H 'Content-type: application/json' \
        --data "${payLoad}" ${rocketUrl})
echo ${statusCode}

@markuman
Copy link

When you got already a dummy user, this ansible collection can post messages to talk conversations.
Maybe it is a workaround for some people, because you can easily integrate it into CI/CD processes.

@FocusDesigner
Copy link

If anyone is interested in @fti7 solution converted to python3, here you go:

* Create an Dummy Nextcloud User

* Create an Channel an get the Channel ID from the URL (in the browser)
import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

However it would still be nice to have some official documentation about this or some official endpoint.

Thanks for the script. This is working as expected.

Sadly it seems I've problems figuring out the right syntax for a get request.
Any chance someone could provide a sample how to get a list of channelIDs or messages?

@David-Development
Copy link
Member

David-Development commented Jul 14, 2021

@FocusDesigner

Any chance someone could provide a sample how to get a list of channelIDs or messages?

Just had a quick look at the Nextcloud Talk Web-UI. As far as I can see they make a request to the following endpoint to receive a list of all channels available on the server (for that user)

https://nextcloud.example.com/ocs/v2.php/apps/spreed/api/v3/room

In terms of messages I'm afraid you need to receive them for each channel seperately

https://nextcloud.example.com/ocs/v2.php/apps/spreed/api/v1/chat/CHANNEL-ID?lookIntoFuture=0&lastKnownMessageId=84&includeLastKnown=1 (replace CHANNEL-ID with the channel you want to receive the messages for - and play around with the query parameters)

@FocusDesigner
Copy link

@David-Development

the v3 did the trick, I always tried v4.
So far parameter lookIntoFuture=0 is the only one I need.

Thanks for your help

@nickvergessen
Copy link
Member

you have to use v4 from Talk version 12 onwards

@mahmoudajawad
Copy link

Has any work been done for this so far?

@BRadHoc
Copy link

BRadHoc commented Dec 1, 2021

I might pick this up again after I've finished the project that I'm working on. We should keep block elements in mind too as this would be good for creating useful applications with formatted data.

The biggest task I believe to start this off would be the authentication mechanism for webhooks, there would need to be generated an individual app key so that an application could provide it in the header of a request sent to Talk and they could be revoked.

@mahmoudajawad
Copy link

@BRadHoc, thanks for replying.

Can I suggest something? Skip the authentication part at the beginning and directly dive into this issue concern, while keeping authentication as simple username/password combination, where any valid user in the setup can be used for this step. I'm suggesting this, as authentication isn't the hurdle here, but more of the implementation of webhooks and applications interface to using Talk, where authentication can be then added based on any known authentication mechanisms.

@rokdd
Copy link

rokdd commented Jan 5, 2022

To get a json response you need to set the accept-header:

import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json','accept': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

@mkrecek234
Copy link

Hi there, Any news on this? Since Talk is able to create guest links - why is it not possible to create a safe webhook link where then any external application can send a message into a chat? I do not want to require a username/password for the bot to be able to post. People should themselves create a webhook link and enter it into any external app. Should be sinple as we have guest support??

@arturrocha
Copy link

To get a json response you need to set the accept-header:

import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json','accept': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

How can we send files?

@mkrecek234
Copy link

@arturrocha The key point is to have a user-generated webhook link. You don't want to have a bot username and password. So everyone can create his own webhook per chat. This is the concept that Slack, Microsoft Teams, Discord, Telegram, and many others use and it makes a lot of sense to integrate the chat in other applications.

@mahmoudajawad
Copy link

To get a json response you need to set the accept-header:

import requests
import json

server = "https://nextcloud.xxx.com"
username = "my-bot"
password = "abc"

def NextcloudTalkSendMessage(channelId, message):
    data = {
        "token": channelId,
        "message": message,
        "actorDisplayName": "PYTHON-NOTIFICATION",
        "actorType": "",
        "actorId": "",
        "timestamp": 0,
        "messageParameters": []
    }

    url = "{}/ocs/v2.php/apps/spreed/api/v1/chat/{}".format(server, channelId)
    # print(url)
    payload = json.dumps(data);

    headers = {'content-type': 'application/json','accept': 'application/json', 'OCS-APIRequest': 'true'}
    resp = requests.post(url, data=payload, headers=headers, auth=(username, password))
    print(resp)
    # print(resp.text)


NextcloudTalkSendMessage('7vijpxv5', 'Hello From Python')

How can we send files?

@arturrocha, are you referring to sending files to webhook (to Talk) or in response of webhook request? If first, the API for webhooks for Talk could implement two formats for sending data (to webhook, Talk) as json and as multipart-form-data, where the second can be used to send complex data including files.

@oneWaveAdrian
Copy link

oneWaveAdrian commented May 12, 2022

Does @David-Development's python script still work? Double checked all variables but all I get is a 404 which would mean the chat was not found. However I copied the important variables such as token and URL from the network tab in the browser, so they have to be correct - what's the issue/missing setting here?

I would need incoming webhooks to display post messages from external tools such as gitlab/uptimerobot etc. in a Talk chat

@erik78se
Copy link

Whats the status on this feature?

I agree on the arguments against needing a username/password to do this since its an obvious security issue to pass around full login capabilities to enable simple message posting.

I'm super keep on getting this functionality available since it would allow me to replace Slack for this purpose.

@mahmoudajawad
Copy link

I'm super keep on getting this functionality available since it would allow me to replace Slack for this purpose.

Same here. I'm looking to replace Teams.

@jancborchardt
Copy link
Member

@nickvergessen
Copy link
Member

All done

@mkrecek234
Copy link

mkrecek234 commented Jan 4, 2024

@nickvergessen Sorry, but I still struggle with the implementation of the new webhook feature. The key logic in all other chat solutions like Slack, MS Teams etc. is that every user can create for example a webhook (i.e. a random tokenized URL to authenticate) that can then RECEIVE messages from other applications and let them post messages into a chat group that the user chooses.

So the steps are:

  1. (Any) user can create a receiving webhook and chooses a chat group where it is allowed to send to - he receives a tokenized URL by Nextcloud Talk
  2. The URL then can be inserted into other apps, like slack who then creates a simple JSON POST to that URL to send messages.

Am I wrong that this is not yet possible? Or that kind of webhook has to be created by the admin? If so, how? (I don't want the webhook to send user chat messages to the outside, only be used to post messages from external apps into defined a defined chat group)

@mkrecek234
Copy link

To add on that: Why not just setup an app username and password and pass this to Slack etc.? Simply because that would allow any third-party service to access my WHOLE Nextcloud and not just push messages to my Talk group

@nickvergessen
Copy link
Member

every user can create for example a webhook (i.e. a random tokenized URL to authenticate) that can then RECEIVE messages from other applications and let them post messages

This is still an open item on the list.

I don't want the webhook to send user chat messages to the outside, only be used to post messages from external apps into defined a defined chat group

I did thinks like this already in couple of places and e.g. we post "notification chat messages" when something was reported in our security bug bounty program. The easiest sample is the one from: #9458

The code inside the if ($config['server']) { is what allows to post a message to a chat.
Not leaking messages of users to the outside is also easily possible. When installing the bot with the occ command specify only the response feature talk:bot:install --feature=response. The bot will then only be able to post messages but never receive messages:

  -f, --feature=FEATURE  Specify the list of features for the bot
                         - webhook: The bot receives posted chat messages as webhooks
                         - response: The bot can post messages and reactions as a response
                         - none: When all features should be disabled for the bot (multiple values allowed)

To add on that: Why not just setup an app username and password and pass this to Slack etc.? Simply because that would allow any third-party service to access my WHOLE Nextcloud and not just push messages to my Talk group

Exactly why we did all this :)

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

No branches or pull requests