slack apiで遊ぶ by Bolt for Python
チャンネル全部取得
conversations.list method | Slack
import os
from slack_bolt import App
# ボットトークンとソケットモードハンドラーを使ってアプリを初期化
app = App(token=os.environ.get("SLACK_USER_TOKEN"))
all_channels = app.client.conversations_list().get("channels")
slack connectで外部にshareされているかどうかとかも各channel
のdictが持っているis_shared
で判別出来る。
チャンネルに招待
conversations.invite method | Slack
import os
from slack_bolt import App
from slack_sdk.errors import SlackApiError
# ボットトークンとソケットモードハンドラーを使ってアプリを初期化
app = App(token=os.environ.get("SLACK_USER_TOKEN"))
# Bot UserのID
bot_user = os.environ.get("BOT_USER")
if __name__ == "__main__":
all_channels = app.client.conversations_list().get("channels")
# print("all_channels", all_channels) # debug
targets = []
for channel in all_channels:
print("channel['name']",
channel['name'],
"channel['id']",
channel['id']) # debug
try:
app.client.conversations_invite(
channel=channel['id'],
users=bot_user
)
except SlackApiError as e:
if e.response.get('error') != 'already_in_channel':
raise Exception
print("already exists")
continue
新規のチャンネルが出来たらそこに招待 TODO
Slack Connectで外部にチャンネルをシェアしたら招待 TODO
スタンプリアクションのリッスン(イベント発火)
reaction_added event | Slack
python - slack API - reaction_added - Stack Overflow
地味にEvent Subscriptions
を忘れがち
先にnekoningen
という名前のスタンプを登録しておく。
# ユーザーが 猫人間 のリアクションをつけたら、Neko !!!と書き込む
@app.event("reaction_added")
def message_hello(say, event):
# TODO
# print("event", event) # debug
reaction = event["reaction"]
if reaction == "nekoningen":
say(f"Neko !!!")
リアクションしたスレッドに返信
『スタンプリアクションのリッスン(イベント発火)』の応用
@app.event("reaction_added")
def message_hello(client, event):
# print("event", event) # debug
reaction = event["reaction"]
if reaction == "nekoningen":
conversations_replies = client.chat_postMessage(
channel=event['item']['channel'],
thread_ts=event['item']['ts'],
text="猫がいたわよ",
)
下ごしらえ諸々 TODO
アプリ登録
アイコン変更
トークンの設定
イベント設定
チャンネルにアプリを追加(手動)
ローカルでとりあえず試すまで TODO
「slack signing secret」と「challengeパラメーター」の話
slack signing secretとは
下記のように、timestampやrequestオブジェクトのbodyの中身を用いて作ったベースの文字列を、signing secret をkeyとしてハッシュ化した値、この値がheadの中のx-slack-signature
の値と等しいかを比較することで、slackサーバーからのリクエストであることを確認している。
// timestampはheaderの`x-slack-request-timestamp`の値
sig_basestring = 'v0:' + timestamp + ':' + request.body()
my_signature = 'v0=' + hmac.compute_hash_sha256(
slack_signing_secret,
sig_basestring
).hexdigest()
>>> 'v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503'
このアタリはslack_sdkのsignature/__init__.py
内のclass SignatureVerifier
内の処理を見ると同じ様なことをやっているのが確認出来る。
challengeパラメーターとは
一般的な「チャレンジ(/レスポンス)認証」とは実際の秘密情報(パスワード)を直接やり取りしないで行う認証方式のことを指す。
具体的に言うと、サーバー側がchallegeと呼ばれる乱数を元に決めた毎回異なるデータ列を送信する。クライアントは利用者が自分の知っているパスワードとして入力した文字列とチャレンジを組み合わせ、これをハッシュ関数を通してハッシュ値に変換したものを「レスポンス」としてサーバに返信する。
サーバは手元の認証情報から正しいパスワードとチャレンジを組み合わせてハッシュ値を算出し、レスポンスと比較・照合する。両者が一致すれば確かにクライアントに入力されたパスワードはサーバ上のものと同一であると確認できる。
The events sent to your Request URL may contain sensitive information associated with the workspaces having approved your Slack app. To ensure that events are being delivered to a server under your direct control, we must verify your ownership by issuing you a challenge request.
各種Eventが起こった時に事前設定したURLに送る情報にはセンシティブなものが含まれる。なので送り先サーバーが本当にアプリ製作者の意図したものなのかを確認するためにchallenge(認証のための)リクエストを行う。
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
token
は(Slackからのリクエストであることの)検証用トークン。『Basic Information』の『App Credentials』にある『Verification Token』の値と同じ値が来ているか見ることで検証出来る。
ただしこれは廃止予定なのであまり気にしなくて良い。この後説明する『Slack Signing Secret』を使うことが推奨されている。
a randomly generated string produced by Slack. The point of this little game of cat and mouse is that you're going to respond to this request with a response body containing this value.
challenge
は(Slack側で)ランダムに作成された文字列。これをそのまま返すことでアプリ製作者の意図したサーバーなのね、とSlack側が認証出来る。
type
はペイロードの種類を表すためのもの。例えば今回ならurlの検証用の1種だと示すurl_verification
という文字列が入っている。
Event Subscriptionでchallengeパラメーターが返ってこないとエラーになる
Your URL didn't respond with the value of the challenge parameter.
(1)直接の原因としてはslackが送ってきたchangeの値をレスポンスで返してやってないから
(2)で、じゃあなぜ返さないのかというとsigning secret前はslackからのリクエストだと判定できないから
でこの説が正しいか見るためにはsigning secretが無くてexceptionとかをappが出してるのを確認取れればまず良い。出来れば雑な生Pythonでsigning secretの確認を取らずにchange paramを返すのだと上手くurl登録できるのかも確認してやれば良い
検証のための前準備
-
Bolt for Pythonのインスール
Slack API を使ったアプリ開発のためのSlack社公式のフレームワーク、のPython版。
Slack | Bolt for Python -
Ngrokへの登録とインスール
ローカル環境のネットワークを一時的に外部公開出来るサービス。
ユーザー登録を下記の公式サイトから行ってから、ngrok
コマンドをダウンロードサイト等からインスールしてください。
ngrok - Online in One Line -
Slack appの登録と
Slack API: Applications | Slackから『Create New App』でアプリを作成する。
その他、細かいことはBolt for Pythonの公式ドキュメントを参考にしてください。
challengeパラメーターが返ってくることを確認
『Event Subscriptions』の『Request URL』ににNgrokが出してくれたURLを入力する。