Teamsボットで湯婆婆を実装してみる

# はじめに

[Javaで湯婆婆を実装してみる - Qiita](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)

今来ているこのビックウェーブに乗って、MS Teamsのボットで「名前を奪ってみようと」思います。

# MS Teamsの送信Webhook
[公式のマニュアル](https://docs.microsoft.com/ja-jp/microsoftteams/platform/webhooks-and-connectors/how-to/add-outgoing-webhook)を見ながらいろいろやっていきます。

## ボットの作成
まずは湯婆婆ボットを作ります。
`チームを管理` > `アプリ` を選択して、右下にある `送信 Webhook を作成` をクリックします。

![Microsoft-Teams2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89477/154c03c5-3917-aaeb-d855-6c7d50954e9e.png)
送信 Webhook を作成していきます。
名前とコールバックURLを指定して「作成」します。
**作成したときにシークレットキーが表示されるので忘れずにメモっておきます!**
これで、Teamsからボットを呼べるようになります。

## コールバック側の処理
なんでもいいんですが、今回は手元に環境があった**Node.js + Express4**で実装します。

まずは**npm**でインストール

```bash
$ npm install express --save
$ npm install body-parser --save
```
で実装はこんな感じ

```js:index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const port = 3001;
const crypto = require('crypto');
const sharedSecret = ''; // ここにシークレットキーを入れてください
const bufSecret = Buffer(sharedSecret, "base64");
let rawBodySaver = (req, res, buf, encoding) => {
        if (buf && buf.length) {
                req.rawBody = buf.toString(encoding || 'utf8');
        }

};
let jsonParser = bodyParser.json();

app.use(bodyParser.urlencoded({
        verify: rawBodySaver,
        extended: true
}));
app.use(bodyParser.json({verify: rawBodySaver}));
app.use(bodyParser.raw({verify: rawBodySaver, type: '*/*'}));
app.post('/ubaba/', (req, res, next) => {
        let auth = req.get('authorization');
        let msgBuf = Buffer.from(req.rawBody, 'utf8');
        var msgHash = "HMAC " + crypto.createHmac('sha256', bufSecret).update(msgBuf).digest("base64");
        //console.log("Computed HMAC: " + msgHash);
        //console.log("Received HMAC: " + auth);
        if (msgHash == auth) {
                next();
        } else {
                res.json({ "type": "message", "text": "Error: message sender cannot be authenticated." });
        }
});
app.post('/ubaba/', jsonParser, (req, res) => {
        let name = req.body.from.name;
        let newName = name.substr(Math.round(Math.random() * name.length) -1, 1);
        res.json({ "type": "message", "text": "フン。"+name+"というのかい。贅沢な名だねぇ。<br>今からお前の名前は"+newName+"だ。いいかい、"+newName+"だよ。分かったら返事をするんだ、"+newName+"!!"});
});

app.listen(port, () => console.log(`Eample app listening on port ${port}!`));
```
起動

```bash
$ node index.js
(node:10057) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Eample app listening on port 3001!
```
Bufferの使い方があまりよくないみたいですが、公式がこう書いているのでいったんそのままにしておきます。

# 使い方としてはこんな感じ
![Microsoft-Teams.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89477/9262eeec-5618-bb8b-f742-ebae5c5d9c52.png)
名前は`req.body.from.name`に入ってくるのでこれを加工してます。

# 苦労した点
[公式のNode.js実装](https://github.com/OfficeDev/msteams-samples-outgoing-webhook-nodejs)では生のNode.jsを使っているので、リクエストボディのデータを素直にとって来れるんですが、expressの場合はBodyParserがパース処理をしてしまうのでハッシュ値の計算がうまくいきません。
そのため、認証部分では生データを使って、「名前を奪う」処理では改めてBodyParserを指定して処理しています。

# 参考記事
[送信 Webhook を使用して Microsoft Teams にカスタム ボットを追加する](https://docs.microsoft.com/ja-jp/microsoftteams/platform/webhooks-and-connectors/how-to/add-outgoing-webhook)
[Node.js Express でPOST本文のRawBodyを取得する](https://www.kwonline.org/memo2/2020/06/18/node-js-express-capture-post-rawbody/)