🦜

Nextcloud Talkのチャットボットを仕様通りに構築する

2024/02/06に公開

TL;DR

  • Nextcloudサーバー上でコマンドocc talk:bot:installで作成する
  • Webhook→トークへのレスポンス
    • レスポンス先
      • NextCloudのURL/ocs/v2.php/apps/spreed/api/v1/bot/{トークID}/message
    • ヘッダ
      • X-Nextcloud-Talk-Bot-Random:任意の64桁16進文字列
      • X-Nextcloud-Talk-Bot-Signature:X-Nextcloud-Talk-Bot-Randomと返信メッセージのバイト列をBot作成時のシークレットを用いてHMACで暗号化した16進文字列
      • OCS-APIRequest:true
    • ボディ
      • JSON:{"message": "返信メッセージ"}

背景

巷に溢れているNextcloud Talkのボットの構築手順記事は、厳密には特定ユーザーのAPIを呼び出してそのユーザーとして投稿するという疑似ボットばかりであり仕様として提供されている本来のボットではないものがほとんどだったので、仕様通りのボットを構築する。

Bot & Webhooks仕様

手順

ブラウザからは設定することができず、直接Nextcloudサーバーにログインしてコマンド実行する必要がある。
またコマンド実行ユーザーはNextcloudの実行ユーザーである必要がある。
Docker版であれば-u 33でコンテナに入る。

前提

  • Botを有効にしたいトークのモデレータであること
  • Docker版での手順

1. Bot作成

command
docker exec -it -u 33 コンテナ名 \
  ./occ \
  talk:bot:install \
  ボット名 \
  シークレット(40文字以上128文字以下) \
  WebhookエンドポイントURL \
  "ボットの説明文字列"

作成確認

command
docker exec -it -u 33 nextcloud \
  ./occ \
  talk:bot:list
+----+---------+------------------+-------------+-------+-------------------+
| id | name    | description      | error_count | state | features          |
+----+---------+------------------+-------------+-------+-------------------+
| 1  | TestBot | Test Description | 0           | 1     | webhook, response |
+----+---------+------------------+-------------+-------+-------------------+

2. Bot有効化

トークの会話設定>ボット>作成したBotをEnableにする。

3. Webhook実装

Flaskで引用付きでオウム返しするBotの例

server.py
import hmac
import json
import secrets
from hashlib import sha256

import requests
from flask import Flask, request


def main() -> None:
    app: Flask = Flask(__name__)

    @app.post("/")
    def nextcloud():
        message: str = json.loads(request.json["object"]["content"])["message"]
        token: str = secrets.token_hex(32)

        print(
            requests.post(
                f"{request.headers['X_NEXTCLOUD_TALK_BACKEND']}ocs/v2.php/apps/spreed/api/v1/bot/{request.json['target']['id']}/message",
                headers={
                    "X-Nextcloud-Talk-Bot-Random": token,
                    "X-Nextcloud-Talk-Bot-Signature": hmac.new(
                        "シークレット".encode(),
                        f"{token}{message}".encode(),
                        "sha256",
                    ).hexdigest(),
                    "OCS-APIRequest": "true",
                },
                json=dict(
                    message=message,
                    replyTo=int(request.json["object"]["id"]),
                    referenceId=sha256(secrets.token_hex(32).encode()).hexdigest(),
                    silent=False,
                ),
            ).text
        )

        return ""

    app.run(host="0.0.0.0", port=Webhookのポート番号, threaded=True)


if __name__ == "__main__":
    main()

4. 動作例

  • トークメッセージ
  • Flaskでの返信POST結果
    <?xml version="1.0"?>
    <ocs>
     <meta>
      <status>ok</status>
      <statuscode>201</statuscode>
      <message>OK</message>
     </meta>
     <data/>
    </ocs>
    

ユーザーのAPI呼び出しとは異なりファイル添付等できず、シンプルなテキストメッセージかリアクションしか投稿できない(トークメッセージのMarkdownには対応)。
またボットのアイコンも簡素な画像なうえ変えられなさそうで、Botとしては最低限のかなり貧弱な機能しか提供されていない。

その他Bot操作コマンド仕様

Discussion