【kintone】 APIトークンの自動生成


まえがき

レコードやアプリの操作は、kintone REST APIでほぼほぼ実装できます。
しかし、通知やAPIトークンといった一部設定値については、kintone REST APIでサポートされておりません。
cybozu developer networkのナレッジノート記事で紹介したPuppeteerを使うと、そんなかゆい所に手が届いたりします。
今回は、APIトークンを自動生成する例を紹介します。

デモ

Puppeteerを使って、APIトークンを自動生成します。

生成したAPIトークンが利用可能か、kintone コマンドラインツールを用いて検証しています。
オプションの「-d」にドメイン名、「-a」にアプリID、「-t」にAPIトークンを指定しています。

コード

Puppeteer、readline-syncを利用しています。 npm等を用いてインストールしてください。

・sample.js (実行コード)

(async () => {
  const readline = require('readline-sync'); //readline-syncの読み込み
  const puppeteer = require('puppeteer'); //puppeteerの読み込み

  //設定値
  const domain = '****.cybozu.com'; //kintoneのドメイン
  const basicUser = false; //Basic認証のユーザー名(設定していない場合はfalse)
  const basicPassword = false; //Basic認証のユーザー名(設定していない場合はfalse)
  const user = '****'; //kintoneのログインユーザー名
  const password = '****'; //kintoneのログインパスワード

  const appId = readline.questionInt('App ID: '); //アプリのID
  const accessRights = []; //追加するAPIトークンに与えるアクセス権
  accessRights[0] = readline.keyInYN('Record view right: ');
  accessRights[1] = readline.keyInYN('Record add right: ');
  accessRights[2] = readline.keyInYN('Record edit right: ');
  accessRights[3] = readline.keyInYN('Record delete right: ');
  accessRights[4] = readline.keyInYN('App edit right: ');

  const browser = await puppeteer.launch(); //ブラウザ起動
  const page = await browser.newPage();
  if(basicUser && basicPassword){ //Basic認証(設定している場合)
    await page.setExtraHTTPHeaders({
      Authorization: `Basic ${new Buffer.from(`${basicUser}:${basicPassword}`).toString('base64')}`
    });
  }
  await page.goto(`https://${domain}/k/admin/app/apitoken?app=${appId}`); //ログインページへ遷移
  await page.type('input[name="username"]', user); //kintoneのユーザー名入力
  await page.type('input[name="password"]', password); //kintoneのログインパスワード入力
  await (await page.$('.login-button')).click(); //「ログイン」ボタンをクリック

  await page.waitForNavigation({waitUntil: "domcontentloaded"}); //APIトークンの設定ページへの遷移を待機
  await page.waitFor('.gaia-admin-app-apitoken-add'); //「生成する」ボタンの描画を待機
  await (await page.$('.gaia-admin-app-apitoken-add')).click(); //「生成する」ボタンをクリック
  const apitoken = await page.evaluate((accessRights) => (
    new Promise(resolve => {
      new MutationObserver(() => { //APIトークンの生成を待機
        const targetRow = document.getElementsByClassName('gaia-admin-app-apitoken-row')[0];
        accessRights.forEach((accessRight, index) => {
          targetRow.childNodes[1].getElementsByTagName('input')[index].checked = accessRight; //APIトークンのアクセス権の変更
        });
        resolve(targetRow.childNodes[0].innerText); //APIトークンの取得
      }).observe(document.getElementsByClassName('gaia-admin-app-apitoken-table-body')[0], {childList: true, subtree: true});
    })
  ), accessRights);
  await (await page.$('.button-submit-cybozu')).click(); //「保存」ボタンをクリック

  await page.waitForNavigation({waitUntil: "domcontentloaded"}); //アプリの設定ページへの遷移を待機
  await page.waitFor('.gaia-admin-app-deploy-button'); //「アプリを更新」ボタンの描画を待機
  await (await page.$('.gaia-admin-app-deploy-button')).click(); //「アプリを更新」ボタンをクリック
  await page.waitFor('.gaia-argoui-dialog-buttons-default-tutorial'); //「OK」ボタンの描画を待機
  await (await page.$('.gaia-argoui-dialog-buttons-default-tutorial')).click(); //「OK」ボタンをクリック

  browser.close(); //ブラウザ停止

  console.log(apitoken); //コマンドラインにAPIトークンを出力
})();

kintoneの仕様変更により、正しく動作しなくなる可能性があります。
予めご了承ください。