Gmailと連携してGitLabのVerification codeをDiscordへ投稿するBotの作り方
こんにちわ、イナトレです。
NeoDuelBot シリーズはご利用者様に対して GitLab でコンテンツ閲覧管理しているのですが、いつ頃からか(すんません、サボってました。2 年ほど前から気がついてました…)新しい IP アドレスからのアクセスに対して Verification code 認証が加わったため zip で最新のコードを提供する形で一時しのぎしていたのですが、格好悪いなと思い改善してみることにしました。
なにげに今まで Discord bot は作ったことがなかったのですが、必要に迫られて GPT4 と会話しながらプログラム作ってました。このプログラムを参考にすれば Gmail と連携して認証する bot なども作っていけると思うので、界隈の参考になればと記事化してる次第。Discord bot 作ったことないよ、って方を対象とした記事にしました。
要件
Gmail を常時 IMAP で監視して GitLab からのVerification code を検知
検知したら code を抽出して Discord の指定 channel へコードを post
30 秒に一回の頻度で処理を loop
Discord での前処理
まずは discord の developers ページへアクセスしてアプリケーションを登録します。
https://discord.com/developers/applications/
色々わかっていない部分も多いのですが、触った感じでは結局いかの赤枠の部分のみを設定すればいいようです。
bot の名前を決める
View Token で Token をメモる。再生成したければ Reset Token する
イメージは DALL-E にでも生成してもらえばよいでしょう
次に bot に権限を付与します。OAuth2 をクリックして、以下の図のようにチェックをしていきます。権限は必要最小限が良いでしょう。今回の要件で言えば 2 権限で問題ありません。
Send Messages
Read Messages / View Channels
一番下の Copy ボタンで bot に権限付与するための URL をコピーします。別タブでこの URL を開くと、以下のような画面が開きます。サーバに追加から、必要となる discord を選んで「はい」を押下することで、指定の discord サーバに bot を招待することができます。
次に連携先の discord サーバの方で bot がメッセージを post する channel を作成します。channel の権限に bot をメンバーとして追加します。一般公開する前までは、プライベートチャネルにして bot のみを追加してテストすると良いでしょう。
最後に channel_id をメモります。post したい channel を選択した状態で、ブラウザの URL を見てみましょう。一番最後の文字列が channel_id です。開発者モードを有効にしている方は、右クリックから id を表示することもできますが詳細説明は割愛します。
Gmail 側の事前設定
次に Gmail 側の事前設定に移ります。Gmail へアクセスして設定画面を開きます。下の図のように右端の「鍵マーク」を押下して、「すべての設定を表示」を押下します。
「メール転送とPOP/IMAP」のタブを開き、以下のように IMAP を有効にします。チェックの状態は、とりあえず以下を真似しておけば良いでしょう。なお POP でも同じようなことができるかと思いきや、メール件数が多いとうまくいかなかったので Bad ノウハウとして覚えておきましょう。
IMAP を有効化したら 2 段階認証プロセスが有効化になっているかを確認します。有効になっていない場合には有効化します。理由は後述。
2 段階認証プロセスを有効化すると、アプリパスワードというものが設定できるようになります。「 2 段階認証プロセス」を押下すると以下のような画面になるので、一番下の「アプリパスワード」を押下します。
アプリ名を入力するとパスワードが発行されます。表示されるパスワードは 4桁 x 4 の文字列です。途中にスペース文字が挟まれていますが、実際は全部連結した 16 文字の文字列として記憶しておきます。このページは一度しか表示されないので、なくしたら新しいアプリとして再登録します。
さて、ここまでで前準備はおしまいですが、アプリパスワードじゃなくてネイティブの Gmail のユーザ名、パスワードでは python プログラムの認証が以下のようなエラーがでて通らなく、少々ハマりました。これが 2FA 認証が必要な理由です。
bot 本体の python3 コード
コピペも面倒でしょうから、discord bot の最終形のソースコードを添付しておきます。まずはダウンロードしてエディターなりで開いてください。
事前設定で取得した各種値を、以下のコードに埋め込んでいきます。channel_id が文字列ではなく数値指定というところがキモです。ここで少々ハマりました。
# Discord Botの設定
discord_token = 'トークンに置き換え'
channel_id = チャネルIDに置き換え # not 文字列
# Gmailの設定
gmail_user = 'usernameに置き換え'
gmail_password = 'アプリパスワードに置き換え'
次に必要なライブラリを pip install します。おそらく下記のコマンドを流しておけば OK かと思います。
pip3 install --upgrade pip
pip3 install discord.py
pip3 install imaplib
コードを読み解くのでしたら、前半の def setup_logging() は読み飛ばしていただいて、以下の 3 つのメソッドあたりを読んでみてください。
async def get_latest_gitlab_auth_message():
....
async def post_to_discord(message):
try:
channel = client.get_channel(channel_id)
logger.debug(f'channel={channel}')
await channel.send(message)
except Exception as e:
logger.exception('Error posting to Discord', e)
@client.event
async def on_ready():
channel = client.get_channel(channel_id)
if not channel:
logger.error(f'Failed getting discord channel: channel_id={channel_id}')
sys.exit()
logger.debug(f'channel={channel}')
logger.info("Bot is ready.")
while True:
await get_latest_gitlab_auth_message()
await asyncio.sleep(30)
await get_latest_gitlab_auth_message()
# ロガーの設定を初期化
logger = setup_logging()
# Discord Botを実行
client.run(discord_token)
処理の流れを大まかに追いかけると、こんな感じの流れになっています。
client.run(discord_token) を呼び出すと import discord で定義された bot 本体が起動されます
準備ができると on_ready() が呼ばれます。 この中で 30 秒に一回の頻度で get_latest_gitlab_auth_message() を呼び出すような loop 処理にしています
get_latest_gitlab_auth_message() 内では、IMAP を使って特定の条件(今回は 'SUBJECT "Verify your identity"' を検索する内容で実装)に一致するメールを検索し、未処理のメールID なら body から Verification code を抜き出して discord に post します
処理が終わったら 2 の loop に戻る
get_latest_gitlab_auth_message() の実装はメールならではのデコード処理やらが実装されているのでご参考までに。なお文中にも書きましたが、pop3 ではじめ実装していたのですが、メールリストが途中までしか取得できず最新の Verification code メールを fetch できなかったため IMAP で実装を行っています。
サーバでプログラムを実行
最後に、作成したプログラムをサーバに配置して起動します。CTRL + C などで強制終了するまで loop して動き続けます。
python3 get_latest_gitlab_auth_message_tmpl.py
裏で動かし続けたい場合は、以下のようにすると良いでしょう。
python3 get_latest_gitlab_auth_message_tmpl.py &
あとはブラウザをプライベートモードで開くなどして、GitLab から認証コードが飛ぶ状態にしてやれば、挙動が確認できます。
あとはご自身の要件に合わせて、get_latest_gitlab_auth_message() の内容をカスタマイズすると良いでしょう。
おしまい。