LoginSignup
2
1

More than 1 year has passed since last update.

現行の GAS では Zoom API の webhook を有効化できない

Last updated at Posted at 2023-02-17

TL;DR

GAS では、以下の要因で Zoom API の webhook を有効化できない。

  • GAS は Zoom API の webhook 有効化に必要なレスポンスを、ステータスコード 302 経由でリダイレクトされた別の エンドポイントから返す。
  • しかし、Zoom 開発者ページの 有効化チェック処理では、インプットボックスに指定したエンドポイント からのレスポンスしか受け付けない。

Zoom APIとLINE Messaging API / Notify APIなどを使って会議の開始をアラートしたりスケジューラと組み合わせたりするのが一時期流行してました。

これを無料で敷居の低いGASで利用できないか、というのも1つ。

しかし、結論として、現状の Google Apps Script でデプロイした 野良API で、現行の Zoom webhook を有効化することは不可能のようです。

これは以下の理由によります。
① Zoom webhook を有効化するには、Zoomの開発者ページで、webhook URLのテスト用の "Validateボタン君"を突破する必要がある。
(ここでの webhook URLとは、GAS でデプロイして発行した URL のこと)

image.png

② 一方、GASで作った野良API は、クライアントからの、デプロイURL への Post リクエストに対するレスポンスを返す際、デプロイURLからではなく、ステータスコード 302 によるリダイレクトを経由し別のエンドポイントから返す。

具体的には、
https://script.google.com/macros/s/++++++++/exec から
https://script.googleusercontent.com/macros/echo?xxxxxx にリダイレクトされ、そこからレスポンスが返ってくる。


下図は、POSTMAN を使い、[Zoom のリクエストをエミュレートしたもの]を、 GAS で発行したデプロイ URL に対して POST したときのコンソール画面。

https://script.google.com/macros/s/++++++++/exec に対するリクエストが、ステータスコード 302(Found) でリダイレクトされ、別の URL(https://script.googleusercontent.com/macros/echo?xxxxxx)からレスポンスが返ってきていることがわかる。

image.png


③ しかし、Validateボタン君は、ページで指定したwebhook URLからのレスポンスしか正当なものと認めない
つまり、GAS 野良 API からの、(302 でリダイレクトされた)別のエンドポイントからのレスポンスを、正当なレスポンスと認めない。(たとえハッシュが正しくても。)

⇒ 現行のGoogle Apps Script の野良APIは、Postリクエストを受けたときそのレスポンスは 302 を経由します。これは設定でどうにかできるものではなさそう。

なので、Zoom API の webhook を使いたい場合は、GAS ではなく Node とか別の手段を使いましょう、ということになるでしょうか。

※この点、LINE Mesaging APIの開発者ページのwebhookの「検証」ボタンでは、GAS でデプロイしたURL でも問題なく通ります。(そもそもLINE Mesaging API の開発者ページにおける「検証」は、そのエンドポイントにアクセスできるかしか調べておらず Validation を行っていないので比較対象にならないかもしれませんが。)


ソースコード(参考)

ちなみに、ZOOM API からの Validation リクエストに対して 正しい内容を吐くGASのコードは下記になります。(ドキュメントをきちんと読めば簡単に作れます)
ただし下記は 上記に書いた GAS の仕様と Zoom 開発者ページの仕様により、検証が通りません。
(もしValidate ボタン君がもうちょっと柔軟な対応をしてくれたら・・・)

const byteToHex = (bytearray) => bytearray.reduce((str, chr) => {
  chr = (chr < 0 ? chr + 256 : chr).toString(16);
  return str + (chr.length == 1 ? '0' : '') + chr;
}, '');

function doGet(e) {
  const output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify({"message":"null"}));
  return output;  
}

function doPost(e) {
  const res = JSON.parse(e.postData.contents);
  const hashForValidate =  byteToHex(
    Utilities.computeHmacSignature(
      Utilities.MacAlgorithm.HMAC_SHA_256, 
      res.payload.plainToken, 
      "***SECRET_KEY***"
    )
  );
  const message = {
    plainToken: res.payload.plainToken,
    encryptedToken: hashForValidate
  };
  const output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify(message));
  return output;
}
2
1
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
1