訳あって、ローカルのファイルサーバのとあるディレクトリを定期的にZIPで固めて、Boxにアップロードするアプリケーションを作成する事になった為、やってみました。この程度フリーソフト使えばいいじゃないか?また、VBAとBox Driveの組み合わせでも良いのではないかと思ったのですが、

ちょっと出来ない理由が出てきてしまったので、作らざるを得ない状況に。electronで作る理由は設定変更などをGUIで簡単にできるようにというのが要件にあるので、以前のようなタスクトレイ常駐型アプリを作る事にします(Linuxでも作れるのですが、Trayモジュールに深刻なバグがあってトレイがうまく動作しない)

※今回準備編はAccess Tokenを取得するまでを挑戦します

難易度:

今回使用するモジュール等

今回の操作上の問題点

今回、このような要件になったのにはいくつかの制限がある為です。

  1. 社内PCにはフリーソフト類のインストールが禁じられている為
  2. 作成したアプリはOKなものの、各担当者のPCを常に起動した状態のままにする事はNGとなる(労務管理上の監視に影響が出る為)
  3. 定期実行(1時間に1回など)を行うのに、VBAで作成するのは厄介である
  4. 認証の関係上、Box Driveを使えない
  5. バックアップ先の変更や定期バックアップの間隔変更などは担当者が行うので設定ファイルではNG(GUIが必要
  6. 仮想環境は直接ネットワーク環境に参加出来ない(仮想マシンのNATで運用する必要がある)

ということで、Node.jsだけで作ろうかなと思ってたのですが、色々と退路を封じられてしまい、Electronがこういった仕事をやらせるには最適かなという事で、このような形になりました。

Box Driveが使えないとなると、Box APIを使ってファイルサーバのファイルをZIPで固めて、日付で名前を付けてアップロードしつづける。故に、Node-Cronも使用する事になります。

事前準備

electronプロジェクトの用意

今回は、以前作成したGraph APIを叩くプロジェクトのようにexpressにてプロジェクトを作成する必要があります。まずは、express-generatorをグローバルインストールする

いつもならば、npm init -yでプロジェクトを作る所ですが、今回は以下のコマンドでexpress-generatorを使ってプロジェクトを作成します。今回はboxmanというディレクトリを作って作業をします。

boxmanというディレクトリが作られて、中にapp.js他たくさんの何かが生成されます。この段階で、以下のコマンドでテストをしてみます。

そして、FireFoxなどでhttp://localhost:3000/にアクセスした場合に、welcome to expressが表示されれば成功です。Ctrl+Cでnpm startしたサーバを停止できます。プロジェクトフォルダ内に空のindex.jsを作成しておきましょう。

既にマシン内で3000番ポートを使用していたり、仮想マシンにポートフォワーディングしているとエラーになるので要注意です。「Unknown authentication strategy “box”」というエラーが出て、認証が出来なくなります。

モジュールを追加する

前項で用意したプロジェクトに対してターミナルより以下のコマンドを入力して、npmでモジュールを追加しておきます。

また、BoxのOAuth2.0認証には、passportおよびpassport-boxを利用して行います。全てのインストールを終えたら、生成されているpackage.jsonを開いて、“main”: “index.js”,をversionの行の次にでも追記して保存します。

keytarに関してはリビルドが必要なので、使う場合にはこちらを参考にネイティブリビルドが必要です。

Boxでプロジェクト作成

Box側ではClient IDClient Secret等を作る必要性があります。以下の手順でBox Developers Portalにて作成しましょう。

  1. Box Developers Portalにログインする
  2. マイアプリにて「アプリの新規作成」をクリックする
  3. 次の画面では「カスタムアプリ」をクリックし、次へ進みます。
  4. 認証方法のページでは、「標準OAuth2.0」をクリックし、次へ進みます。
  5. アプリの名前は適当に設定し、「アプリの作成」をクリックします。アプリ名は同じものが設定できませんので注意!!
  6. アプリの表示をクリックして設定データを取得しておきます。
  7. OAuth2.0資格情報の欄にて、クライアントIDおよびクライアント機密コード(Secret)をコピーして控えて置きます。
  8. OAuth2.0リダイレクトURIですが、ローカルアプリなので「http://127.0.0.1:3000/auth/box/callback」を入れておきます
  9. アプリケーションのスコープでは、許可するアクションにチェックを入れます。
  10. 高度な機能では、「ユーザとして操作を実行」を有効にします。
  11. CORSドメインはウェブなどで利用する場合に許可送信元として入力する場合にそのサイトのドメインを入れておきます。
  12. 変更を保存するボタンをクリックして完了

リダイレクトURLではlocalhostの3000版にリダイレクトさせるようにしています。

図:リダイレクトURLの設定が嵌りどころだったりします。

expressのテスト

index.jsにとりあえず以下のテスト用コードを追記してみる。npm startでexpressのサーバを起動した状態で、electron .で起動してみて、welcome to expressが表示されればテストはOK。

しかし、このままでは別途npm startでexpressを立ち上げて置いてから、electron .で起動する必要があるため、package.jsonscriptsのラインにnpm-run-allを使って複数のタスクを同時に起動するように細工をします。これで、テスト時は、electron .だけで全て起動します。

図:expressサーバをelectronから開けた

社内プロキシーを越える

社内向けのアプリを作る上での実は一番の障害は、「プロキシーサーバ」だと思います。npmにしかり、electron、expressそれぞれにプロキシーを超える設定をする必要がある場合があります(特に大企業の場合、普通にプロキシーサーバ経由になってる場合が多く、これを超える設定を行わないと、外部と通信が出来ない)

electron側の設定

こちらは簡単です。プロキシーサーバもしくはプロキシーのpacファイルの指定を1行追加すれば、外部との通信が可能になります。これを入れておかないと、外部のCSSなどもロードされないので、注意。

社内プロキシ環境下で設定無しでpassport-boxにて認証をしAccess Tokenを取得しようとすると「InternalOAuthError: Failed to obtain access token」というエラーが出て、プロセスが停止してしまいます。

図:プロキシー経由させずにDNSエラーが出る

パッケージを追加

今回、expressをプロキシーの背後で動かす為に、httpx-proxy-agent-configというモジュールが必要でした。公式サイトなどでのコマンドラインで打つとインストールが出来ません。

関連モジュールもインストールされて、これでexpressからプロキシー経由で外に出る事が可能です。また、requestモジュール等にも別途Proxy設定せずとも有効になるので、非常に便利なモジュールです。

express側の設定

expressのapp.js側に追加するコードは以下の通り。

たったこれだけです。http_proxyhttps_proxyは環境によっては同じURLで問題ないかと。ただし、blacklistについてコメントアウトしてありますが、blacklistに入れたものはこのモジュールがブロックするので、注意してください。今回はelectronがlocalhost:3000にアクセスする必要があるので、localhostなどもblacklistには入れません。

以降のexpressの外部への通信はすべてプロキシー経由になります。

一部のパッケージの為に

一部のnpmモジュールに於いて(例えば、electron-packagerなど)、利用時にプロキシ越え出来ずにエラー(ENOTFOUND github.com)が出る場合があります。環境変数にプロキシ設定をセットしたはずなのに。。

ということで調べてみたら、electron本体ではVersion7.0以降、また一部のこういったモジュールでは、最新版より環境変数の参照先が変更されているようです。ということで、Windowsの環境変数に以下の設定を追加します。

  • ELECTRON_GET_USE_PROXY:値はtrue
  • GLOBAL_AGENT_HTTP_PROXY:値はhttpから始まるプロキシアドレス:プロキシポート
  • GLOBAL_AGENT_HTTPS_PROXY:値はhttpから始まるプロキシアドレス:プロキシポート

セットしたら、さっそくelectron-packagerでパッケージングを実行してみたところ、エラーが解消し無事にパッケージの作成が成功しました。今後他のモジュールも移行していくのかもしれません。

ソースコード

ここからが一番の峠道です。通常であればindex.jsに色々と記述する所ですが、今回の認証アプリの場合には、app.jsの方に記述する事になります。自動生成されたapp.jsにはすでに色々記述されているので、これを改造して使います。

今回は、こちらのソースコードを利用しています(少し改変を加えています)。また、利用するejsファイルについてもexampleにあるものを追加しています。

app.js側コード

  • Microsoft Graph APIを叩くコードとほとんどが同じになります。このモジュールの良い点です。
  • http-proxy-agent-configによるプロキシを透過する為の設定を冒頭に入れてあります。
  • electron-storeに格納されているClient IDとClient Secretを用いて、BoxStrategyにて認証を実行します。
  • 初期ページ、ログイン用ページなどのejsファイルはexpressにてREST APIのように構築しています。コールバック先URLもこれで実現。
  • Access Token書き出し用のルーチンは次回以降作成します。
  • 初回起動時はClient IDなどがセットされていないので、passport.useを実行しないように判定を入れています(エラーになってしまうため)
  • ちなみに、electronで実行しアプリを立ち上げると、ウェブブラウザでhttp://localhost:3000にアクセスすると普通に認証ページが開けたりします。遠隔でアプリの設定変更や、認証の実行などが可能です。

index.js側コード

  • setCronJobにて今回は設定値にある時間を持って、何時間毎に実行するかを指定します。
  • Electron自体をプロキシ越えられるようにする為のapp.commandLine.appendSwitchを入れてあります(今回はpacファイルを指定する)
  • タスクトレイ常駐型アプリなので、その為の一連の設定を入れてあります。
  • boxauthにて、express側のlocalhost:3000番ポートをelectronで表示させています。これが認証用の入り口になります。
  • 今回はフォルダダイアログ(openDirectory)にて、バックアップするフォルダを指定する機能を付け加えています。
  • updatefolderは実際にバックアップするルーチンですが、次回以降作成します。

setting.html側コード

各種設定を保存する為のセッティング用ウィンドウのファイルになります。今回は、同期するフォルダ・BoxフォルダID・同期間隔・Client ID・Client Secretの5項目(これに次回暗号化用のパスワード欄も)を保存できるようにします。

図:アプリの設定ダイアログ

関連リンク

共有してみる: