DiscordでBOTを動かすときの制作ガイドライン

## この記事を見るにあたって
この記事はDiscordでBOTを作りたい！という人に向けた簡単な作り方と絶対に抑えるべき注意点を紹介する記事です。
注意点を遵守すれば安全で楽しいDiscordBot開発への1歩になります。

なお、この記事は私の所属している[限界開発鯖](https://approvers.dev)の複数人で共同執筆したものを私が体裁を少々整えたものになります。

## BOT作成のための簡易 *FLOW CHART*

1. [Discordの開発者ポータル](https://discord.com/developers/applications) でApplicationを作成。
2. BOTページにて名前やアイコンを決める。
3. OAuth2ページのScopesで *bot* にチェックを付けると、*bot permissions* が表示される)
    1. ここでメッセージの読込、書込、絵文字追加等の BOT のアカウントのようなものに対する権限を選べる
    2. BOT の招待 URL がここで選んだ権限設定で生成される
    3. これは招待 URL 生成ツールなので、保存されるわけではないから注意

このとき、***Administratorは選択しないでください!!***
Administrator (管理者権限) は冗談抜きでマジのマジにでかい権限であり、**些細なミスで所属サーバーを破壊することも十分ありえます**。***絶対にやめましょう***。


![scopes](https://i.imgur.com/8GWcYYP.png)

![bot_permissions](https://i.imgur.com/7R6LEmY.png)


\* ここでサーバーに招待する人は **管理者権限が必要** です。管理者にコンタクトを取ってBOTが要求する権限をチェックしてもらうといいでしょう。

![bot_invitation](https://i.imgur.com/BM1xjay.png)

管理者権限を持った人にこのURLを開いてもらうと、認可画面を経て、BOTが招待されます。

上記の一連の操作でBOTを作成できます。すると、Tokenという「BOTを動かすため (正確にはDiscord API にアクセスするため) の文字列」が生成されます。

Tokenはユーザーの ***PASSWORD*** と同義です。***絶対外に漏洩しないようにしましょう***。乗っ取られて攻撃に使用されたときに責を問われるのはBOT作成者である **あなた** です。***絶対に漏洩しないようにしましょう***。

Tokenを漏らすとDiscord運営が自動で失効してくれたりしますけどね。

実際に高専生でDiscordの***サーバーを吹っ飛ばしてしまった***例も存在します。
[***この記事***](https://qiita.com/mochizukikotaro/items/a0e98ff0063a77e7b694) は ***AWSのシークレットキーとアクセスキーを漏洩した人の話*** ですが、こういった被害に遭うことはTokenの漏洩でも十分に起こりえます。


## テンプレート

ここに書いてあるテンプレートを基にBotを作成すれば、別記注意点をだいたい満たせるはずです。
**が、** あなたが考慮すべき点も多々あります。
どちらの例も、環境変数 `DISCORD_TOKEN` にトークンを入れることを想定しています。
`dotenv` などを使っておくとローカルでのテストが少し楽になるかもしれません。

### TypeScript

```typescript
import { Client, Message } from 'discord.js';

// partials で必要な権限を設定する必要あり
const client = new Client({ partials: ['MESSAGE', 'CHANNEL'] });

client.on('ready', () => {
    // ここに起動したときの処理
    console.log('準備完了');
});

client.on('message', async (msg: Message) => {
    if (msg.author.bot) {
        return;
    }
    // ここにメッセージを受信したときの処理
});

client.login(process.env.DISCORD_TOKEN || 'no_token_found');
```

### Python

```python
import discord
import os

class Client(discord.Client):
    
    async def on_ready(self):
        # 起動時の処理
        pass
    
    async def on_message(self, message: discord.Message):
        if message.author.bot:
            return
        # メッセージを受信したときの処理

Client().run(token=os.environ["DISCORD_TOKEN"])
```

### Golang

```golang
package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/bwmarrin/discordgo"
)

func main() {
	session, err := discordgo.New()
	if err != nil {
		fmt.Println("Error in create session")
		panic(err)
	}

	discordToken := loadToken()
	session.Token = discordToken

	session.AddHandler(onMessageCreate)

	if err = session.Open(); err != nil {
		panic(err)
	}
	defer session.Close()

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)

	fmt.Println("booted!!!")

	<-sc
	return
}

func onMessageCreate(session *discordgo.Session, event *discordgo.MessageCreate) {
	if event.Author.Bot {
		return
	}
	/* メッセージを受け取った際の処理 */
}

func loadToken() string {
	token := os.Getenv("DISCORD_TOKEN")
	if token == "" {
		panic("no discord token exists.")
	}
	return token
}
```

## 注意点

- ***†Botに管理者権限をつけないでください†***
- Botに付けるのを控えるべき権限
    - Administrator
    - Kick Members
    - Ban Members
    - Manage Server　　
    
    これらの権限は極力管理者しか持たないようにするのが理想です。
- ***Botのメッセージに返答する機能は実装しないでください！***
  BOT同士で返答し合うような組み合わせが発生してしまった時に、延々と処理を実行してしまったり、通知などでサーバー全体に迷惑をかけることになります。
  これをしないと、最悪権限を切ることになってしまいます。
- ボットによる言論統制をしないこと、以下に言論統制に該当するものを示します。
    1. メッセージ自動削除
    2. メッセージ内容の誘導
- ***TOKENをソースコードに直接書かないでください！！！***
  上にも記述しましたが、**TOKENはパスワード** です。当然、パスワードをインターネット上にアップロードするのはいけませんね？TOKENを扱う際は十分に気を付けてください。
  GitHub などにあげる際は充分に注意してください。

### トークンをアップロードしないための技術

以下のようなものがあります。

- プログラムの実行時引数でトークンを渡す
- デプロイ環境の環境変数を設定してプログラム内で読み取る
- `dotenv`を使用する。
    - これに関しては言語によって存在する場合もしない場合もあるので自分の使う言語に合わせて検討してください。
      テンプレートの言語における参考記事です。
        - Python: https://qiita.com/harukikaneko/items/b004048f8d1eca44cba9  
        - node: https://qiita.com/ozaki25/items/3e2cf94f29bd0edc1979
        - Golang: https://qiita.com/sola-msr/items/fb7d6889d7bd7a6705d0

**別のファイルから読み込むなどもよくありません。** (`.gitignore` などでアップロードを防げば大丈夫ですが、くれぐれも ignore 洩れには気をつけてください。)

### 追記
- 2020/07/08時点
    Golangにおけるトークン読み込みやセッション作成失敗時の処理を`panic`に変更、それに伴うコード整形を行いました。
    コードがどう変わったかについては[こちら](https://github.com/approvers/discordbot_template_golang/pull/2)