Closed4
DiscordのSlash Commandをwebhookで受信する方式で作ってみる
スラッシュコマンドについて
Documentation Slash Commands
- public developer beta だよ
- コマンドはアプリケーションに登録する
- コマンドの登録には
applications.commands.update
スコープの承認が必要
- コマンドの登録には
- コマンドは {名前, description, optionブロック} で構成される
- optionはユーザー入力を検証する
- コマンドはアプリケーションが追加されたギルドで使用できる
- アプリケーションはギルドに
applications.commands
スコープの承認を持つ必要がある- ギルドの管理者権限を持つユーザーにブラウザで承認要求URLにアクセスさせ承認を得る
- 承認要求ダイアログでそのユーザーが管理者権限を持つギルドのリストからアプリケーションを追加するギルドを選択する
- ギルドの管理者権限を持つユーザーにブラウザで承認要求URLにアクセスさせ承認を得る
- ギルドに追加されたアプリケーションはDiscordクライアントに表示される
- 「サーバー設定」->「連携サービス」->「Botおよびアプリ」に表示される
- ギルドにBotユーザーを追加せずにアプリケーションとやりとりができる
- アプリケーションはギルドに
- アプリケーションは特定のギルドでのみ有効なコマンドも持つことができる
- ユーザーがコマンドを使用するとアプリケーションはメッセージを受け取る
- メッセージにはguild_id, channel_id, memberなどのメタデータが付加される
interaction : やりとり、interaction id
- ユーザーがコマンドを使うとinteractionが開始する
- アプリケーションはinteractionを受け取り、応答を返す
webhookでinteractionを受信する
アプリケーションにInteraction Endpoint URLを設定すればwebhookが有効になる。webhookが有効になったらgatewayにはinteractionのイベントは送信されなくなる。endpoint urlを設定するときにはdiscordから確認のping が送信されるので、pong応答をすること。
webhookのHTTPリクエストは署名の検証をすること。失敗したら401を返すこと。定期的にセキュリティチェックが実施される(検証に失敗するリクエストが送られるのかな)、ちゃんと検証してなかったらアプリケーションのendpoint url が削除される。
interactionへの返信もwebhook。なので、botでのメッセージ送信と適用される制限が違うので注意。
- 1つのinteractionへ複数の返信が可能
- 送信した返信を編集、削除することが可能
- interactionへの最初の返信(initial response)は3秒以内
- interactionの有効期間は15分
- なのでこの時間内であれば追加の返信、送信済みの返信の編集と削除が可能
アプリケーションにコマンドを登録する
コマンド登録HTTPエンドポイントへコマンド{name, description, options}をPOSTすればコマンドが登録できる。このリクエストにはアプリケーションのapplicaitons.commands.update
スコープのClient Credentials Tokenが必要。
client credentials tokenの取得方法はこちら。docsのコード例はpython。
import requests
import base64
CLIENT_ID = ''
CLIENT_SECRET = ''
APPLICATION_ID = ''
GUILD_ID = ''
def get_token():
data = {
'grant_type': 'client_credentials',
'scope': 'applications.commands.update'
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('https://discord.com/api/v8/oauth2/token', data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()['access_token']
url = f"https://discord.com/api/v8/applications/{APPLICATION_ID}/guilds/{GUILD_ID}/commands"
json = {
"name": "blep",
"description": "Send a random adorable animal photo",
"options": [
{
"name": "animal",
"description": "The type of animal",
"type": 3,
"required": True,
"choices" : [
{
"name": "Dog",
"value": "animal_dog"
},{
"name": "Cat",
"value": "animal_cat"
},{
"name": "Penguin",
"value": "animal_penguin"
}
]
},
{
"name": "only_smol",
"description": "Whether to show only baby animals",
"type": 5,
"required": False
}
]
}
headers = {
"authorization": "Bearer " + get_token()
}
r = requests.post(url, headers=headers, json=json)
Interaction Endpointを用意する
discordからのwebhookを受け取るHTTPエンドポイントを実装する。
Ed25519の鍵での署名を検証する必要がある。
どこに作るか
- Azure API Managementならポリシー式で署名の検証が出来そう
- 現在のポリシー式では出来ないっぽい、EdDSAに対応してない
とりあえず、GCP Functions の認証なしHTTPトリガーでやってみる
- 課金が有効なGCPプロジェクト
- プロジェクトで functionsとbuildのAPIが有効
gcloud functions deploy commands --runtime nodejs14 --trigger-http --allow-unauthenticated --set-env-vars CLIENT_PUBLIC_KEY=<discord app の public key>
discord提供のwebhook受信用のjsライブラリ
署名の検証関数と定数の定義が提供される
署名を検証して内容がコマンドでなければPONG応答を返す。
// https://github.com/discord/discord-interactions-js/blob/main/examples/gcloud_function.js
// 使用していない変数を削除した
const { InteractionResponseType, InteractionType, verifyKey } = require('discord-interactions')
const CLIENT_PUBLIC_KEY = process.env.CLIENT_PUBLIC_KEY;
exports.commands = async (req, res) => {
const sig = req.get('X-Signature-Ed25519');
const time = req.get('X-Signature-Timestamp');
const isValid = await verifyKey(req.rawBody, sig, time, CLIENT_PUBLIC_KEY);
if (!isValid) {
return res.status(401).send('invalid request signature');
}
const interaction = req.body;
if(interaction && interaction.type === InteractionType.COMMAND) {
res.send({
type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
data: {
content: `You used: ${interaction.data.name}`
},
});
} else {
res.send({
type: InteractionResponseType.PONG,
});
}
};
このスクラップは2021/11/28にクローズされました