Box APIとの通信をCharles Proxyを通して覗き見る方法

##　BOX SDK、BOX CLIがBOX APIとしている通信を覗く

BOXのCLIやSDKをつかって、BOX APIを実行するとき、APIの通信内容が見れると、問題の原因を特定できたり、デバッグがはかどったりなど、便利なことが多いです。BOX APIはHTTPSで通信しているため、基本的には外から通信内容を覗き見ることはできません。ただし、ProxyとしてSDKとAPIの間に入ることで中身を覗くことができる、man-in-the-middle HTTPS proxy というジャンルのアプリを使うことで、通信内容を覗くことが可能です。
このジャンルのアプリのの一つで、自分がよく使っているCharlesというアプリで、BOX SDKやCLIがAPIとの通信内容を覗き見る方法を紹介していこうと思います。

Charles
https://www.charlesproxy.com/

Charlesは、有料のアプリですが、試用期間中は無料で使うこともできます。
なお、私が利用している環境はMacで、バージョン4.6.2のCharlesをつかっています。
特にMac以外の方は少し使い方がちがうかもしれません。Windowsの人はその点読み替えてください。


## Charlesの設定

基本的に、Charlesの使い方や設定方法は、本家の[Documentation](https://www.charlesproxy.com/documentation)に書いてあるので、ここを読んでください、なんですが、ここでは大切なところだけ書いておきます。

#### ルート証明書をOSに入れておく
Macの場合、Help -> SSL Proxying -> install Charles Root Certificateをクリックします。
Macの場合は、キーチェーンが開くので、ここで常に信頼する設定にします。
これで、Proxy -> macOS Proxyにチェックをつけておくだけで、ブラウザや、.NET SDKのHTTPS通信の中身が見れるようになります。

詳細はこのドキュメントをみてください。
https://www.charlesproxy.com/documentation/using-charles/ssl-certificates/


## Box Node SDK　の通信を覗く

Node.jsは、Proxyの向き先を指定する必要がるのと、OSのキーチェーンの証明書を利用してくれないので、すこし工夫が必要になります。
以下の手順でNode.jsにCharlesのルート証明書を使わせ、Proxyの指定をコード内で行うひつようがあります。

1.Charlesのルート証明書を保存する
Help -> SSL Proxying -> Save Charles Root Certificate ...
適当な場所に保存します。

2.環境変数に保存したルート証明書の位置を入れる
`NODE_EXTRA_CA_CERTS`に、ステップ1で保存したpemファイルを指定します。

例えば、zshを使っている筆者の環境では以下のような文を.zshrcに入れています
`export NODE_EXTRA_CA_CERTS=/Path/To/charles-ssl-proxying-certificate.pem`

3.CharlesのProxy設定で、Socksプロキシモードを有効にする

Charles → Proxy → Proxy Settings... 
SOCKS Proxy Modeを押す。

<details><summary>スクリーンショット</summary>
![スクリーンショット 2021-12-21 21.57.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45767/1bfa9ccc-6a79-4496-b1ed-a11e2b748602.png)
</details>

4.コードにProxyの設定を書き込む

```js:sample.js
const boxSDK = require("box-node-sdk");
const config = require("./XXX_config.json");
const sdk = boxSDK.getPreconfiguredInstance(config);

// Proxyの設定 ここから
sdk.configure({
  proxy: {
    url: "socks://localhost:8889", 
  },
});
// Proxyの設定 ここまで

const client = sdk.getAppAuthClient("enterprise");
client.users.get(client.CURRENT_USER_ID).then(me => console.log(me));
```

5.通信内容を確認

ステップ4のアプリを実行すると、HTTPSの通信内容を確認可能です。

<details><summary>スクリーンショット</summary>
![スクリーンショット 2021-12-21 22.40.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45767/c61f2b11-81b3-5dbe-11c3-94d16e99d4a6.png)
</details>

## Box Python SDK　の通信を覗く

Pythonの場合、コードでProxyの向き先を指定をする必要がありません。
CharlesのmacOS Proxyだけで、通信をキャッチしてくれます。
ただし、Charlesのルート証明書が入っているとエラーになってしまいます。
これを防ぐために、SDKに一箇所手を入れます。

この作業は、Box Python SDKの以下のファイルを直接編集します。
boxsdk/network/default_network.py

およそ29行目から、def requestがはじまりますが、以下のように`verify=False`を追加します。

```py:boxsdk/network/default_network.py
    def request(self, method, url, access_token, **kwargs):
        self._log_request(method, url, **kwargs)
        # pylint:disable=abstract-class-instantiated
        try:
            return self.network_response_constructor(
                # ↓ この行をコメントアウトし、1つ下の行を追加。verify=Falseを追加している。
                # request_response=self._session.request(method, url, **kwargs),
                request_response=self._session.request(method, url, verify=False, **kwargs),
                access_token_used=access_token,
            )
        except Exception:
            self._log_exception(method, url, sys.exc_info())
            raise

```

これで通信内容がCharlesで見れるはずです。
もっといいやり方があればおしえてください。
理由の調査ができていませんが、なぜか、この改造をしなくても通信が見える環境もありますのでまずはエラーが出ることを確認してから改造されたほうがいいかもしれません。

## Box Java SDK　の通信を覗く

Javaの場合、jreの中にCharlesのルート証明書を追加する必要があります。
Charles → Help → SSL Proxying → Install Charles Root Certificate in Java VMs
を実行すると、全てのJava VMにインストールしてくれます。
これだけで、CharlesでHTTPSの通信がキャプチャ可能です。

<details><summary>スクリーンショット</summary>
![スクリーンショット 2021-12-22 8.49.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45767/12d88302-2c68-79c3-9bf2-696613f99873.png)
</details>

特定のjreのみにインストールしたい場合など、マニュアルで実行する方法は以下にかかれています。
Java Applicationsの箇所を参照。
https://www.charlesproxy.com/documentation/using-charles/ssl-certificates/

このマニュアルには、$JAVA_HOME/jre/lib/security/cacerts と書かれていますが、
自分の環境では、$JAVA_HOME/lib/security/cacertsの位置にありました。。


## Box .NET SDK　の通信を覗く

.NETの場合は、MacのキーチェーンにCharlesのルート証明書を入れるだけで動作しました。
ちなみに .NET Coreだけで試しました。.NET Frameworkだとどうなるかわかりません。


## Box CLI の通信を覗く

Box CLIは内部でBox Node SDKを使っているので、基本的な考え方はBox Node SDKと同じです。
設定するためのコマンドがあるのでこれを解説します。

Box Node SDKの箇所で書いた、以下のステップを実施します。
1.Charlesのルート証明書を保存する
2.環境変数に保存したルート証明書の位置を入れる
3.CharlesのProxy設定で、Socksプロキシモードを有効にする

以下のコマンドでプロキシの向き先をセットします

```sh
$ box configure:settings --proxy-url=socks://localhost:8889 
```

以下のコマンドでプロキシの有効/無効を切り替えることができます

```sh
$ box configure:settings --no-enable-proxy # disables the proxy
$ box configure:settings --enable-proxy # re-enables the proxy
```

これでCharlesでHTTPSの通信内容を覗くことができます。


参考：Box CLIのProxyの設定方法はこの記事が詳しいです。
https://medium.com/box-developer-blog/box-cli-adds-proxy-support-b67e930cf614