LoginSignup
2
3

More than 1 year has passed since last update.

【LINE WORKS】Node.jsでオウム返しBotを作る【API 2.0】

Posted at

はじめに

今回は、Node.jsによるAPI2.0に対応したBot実装例を、シンプルなオウム返しBotをベースにまとめてみる。

ソースコード

具体的な実装は以下を参照。Express を使用した。

以下、実装内容について一部抜粋して解説する。

実装解説

  • 環境: Node.js 16

改ざんチェック

LINE WORKS APIのBotには、Callbackで受け取ったRequest Eventの改ざんチェックを行う機能がある。

参考 : https://developers.worksmobile.com/jp/reference/bot-callback?lang=ja

Request headerの X-WORKS-Signature によって渡される署名と、Developer ConsoleのBot画面で発行されている Bot Secret を用いて、Request bodyの改ざんチェックを行う。

以下、コード例。

var crypto = require("crypto");


let safeCompare = (a, b) => {
    if (a.length !== b.length) {
        return false;
    }
    return crypto.timingSafeEqual(a, b);
};


/**
 * Validate request
 * @param {Object} body - Request Body
 * @param {string} signature - value of X-WORKS-Signature header
 * @param  {string} botSecret - Bot Secret
 * @return {boolean} is valid
 */
let validateRequest = (body, signature, botSecret) => {
    return safeCompare(
        crypto.createHmac("SHA256", botSecret).update(body).digest(),
        Buffer.from(signature, "base64"),
    );
};

Access Token取得

送られてきたメッセージへのリプライにはAPIを利用する。APIの利用のためにまずはAccess Tokenを取得する。

「Service Account認証」というJWTを使った認可の仕組みを使ってAccess Tokenを取得する。

参考 : https://developers.worksmobile.com/jp/reference/authorization-sa?lang=ja

Access Token取得までの流れ。

  1. (事前準備) Developer ConsoleからAppを作成し、以下の各種認証情報を設定・取得する。
    • Client ID
    • Client Secret
    • Service Account
    • Private Key
    • OAuth Scopeの設定
  2. JWTの生成。以下の情報を利用。
    • Client ID
    • Service Account
    • Private Key
  3. Access Tokenを取得する。以下の情報を利用
    • 生成したJWT
    • Client ID
    • Client Secret
    • 必要なScope
      • 今回はBotへの返答を行うのみであるため bot scopeを指定する。

以下、Access Token取得のコード例。

const jwt = require('jsonwebtoken');
const axios = require("axios");

/**
 * Generate JWT for access token
 * @param {string} clientId - Client ID
 * @param {string} serviceAccount - Service Account
 * @param {string} privatekey - Private Key
 * @return {string} JWT
 */
let getJWT = (clientId, serviceAccount, privatekey) => {
    current_time = Date.now() / 1000;
    iss = clientId;
    sub = serviceAccount;
    iat = current_time;
    exp = current_time + (60 * 60); // 1 hour

    jws = jwt.sign(
        {
            "iss": iss,
            "sub": sub,
            "iat": iat,
            "exp": exp
        }, privatekey, {algorithm: "RS256"});

    return jws;
};


/**
 * Get Access Token
 * @async
 * @param {string} clientId - Client ID
 * @param {string} clientSecret - Client Secret
 * @param {string} serviceAccount - Service Account
 * @param {string} privatekey - Private Key
 * @param {string} scope - OAuth Scope
 * @return {string} Access Token
 */
let getAccessToken = async (clientId, clientSecret, serviceAccount, privatekey, scope) => {
    const jwt = getJWT(clientId, serviceAccount, privatekey);

    const params = new URLSearchParams({
        assertion: jwt,
        grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
        client_id: clientId,
        client_secret: clientSecret,
        scope: scope,
    });

    const res = await axios.post("https://auth.worksmobile.com/oauth2/v2.0/token", params);

    const accessToken = res.data.access_token;

    return accessToken;
};

メッセージリプライ

リプライには「メッセージ送信」のAPIを使う。

送信先ユーザーに、Request bodyの source.userId を指定し、コンテンツには送られてきたテキストをそのまま指定する。

{
    "content": {
        "type": "text",
        "text": "{Reply text}"
    }
}

参考 : https://developers.worksmobile.com/jp/reference/bot-send-text?lang=ja

また、API呼び出し時に先ほど取得したAccess Tokenを Authorization headerに指定する。

Authorization: Bearer {{Access Token}}

メッセージ送信のコード例は以下の通り。

const axios = require("axios");


/**
 * Send message to a user
 * @async
 * @param {Object} content - Message Content
 * @param {string} botId - Bot ID
 * @param {string} userId - User ID
 * @param {string} accessToken - Access Token
 * @return {Object} response
 */
let sendMessageToUser = async (content, botId, userId, accessToken) => {
    const headers = {
        Authorization: `Bearer ${accessToken}`
    };

    const res = await axios.post(`https://www.worksapis.com/v1.0/bots/${botId}/users/${userId}/messages`, content,
        { headers }
    );
    return res;
};

API利用時の考慮

注意点として、APIリクエストにはRate Limitが設けられており、制限を超えた際は429のエラーが返る。その際は時間を置いて再送する必要がある。そのため、それを考慮した再送処理を実装する必要がある。

加えて、Access Tokenも期限切れがあるため、再発行の処理も追加する。

詳しくはソースコードを直接参照ください。

まとめ

Node.js + Expressを使ったAPI2.0対応のLINE WORKS Botの実装例をまとめた。
API1.0からの移行としては、改ざんチェックやAccess Token取得の部分など、API1.0のBotのコードから流用できたものが多い。

もしこれらサンプルに不具合がある場合は、この記事のコメントもしくはGithubリポジトリのIssuesでお知らせください。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3