見出し画像

正解のない問題に答える:kintoneプラグインのライセンスを管理する設計

はじめに

先日公開したkintoneプラグイン「Slack通知V」「印刷レイアウトV」は、もう試していただけましたか?今回は私たちがプラグインのライセンス管理をどのように設計したのかについて説明したいと思います。今回、私たちは無料プラグインでもライセンス管理、顧客管理を行っていますが、有料プラグインを販売する場合なら、これらは絶対に必要な要件になるはずです。
ライセンス/顧客管理について公式のドキュメントは存在しておらず、また、他社さんの技術記事のようなものも見つからない現状で、私たちの設計が皆さんの参考になれば幸いです。

プラグインの作り方はわかるが…

kintoneの標準機能だけでは実現できない要求がある場合、それは「JavaScriptカスタマイズ」か「プラグイン」で実装するのが一般的なようです。特にプラグインはユーザー側から見た導入のしやすさがあり、どちらでkintoneの機能を拡張するのか?と言われたら、今の私たちならプラグインを選びます。
プラグインの実装方法についてはサイボウズのドキュメントが存在しますし、プロジェクトファイルのscaffolding(足場組み、つまり必要なファイルを自動生成すること)についてはcreate-pluginライブラリが提供されていますので、いきなりコーディングを始めて、デプロイまで自動で行うことができます。これはとても楽ですので、利用することをお薦めします。それにこれがサイボウズがお薦めする「プラグイン開発のお作法」なのだとしたら、まずはそれに従って作るのが当然だと思います。

しかし、上記のドキュメントには「どのようにして有料プラグインのライセンス管理を行うのか」については触れられていません。ネットで検索すれば、他社さんが公開している有料プラグインはたくさんあるようです。皆さん、一体どのような実装をしているのでしょうか?これには私たちも最初は戸惑いました。そして既存の有料プラグインの申し込みフォームを見ていると、 サブドメイン の入力欄が必ず存在することに気づきました。つまり「顧客管理DB」を作るとしたら、その複合キーはライセンスキー(これは動的に発行する)とサブドメインになりそうです。この2つの情報があれば「誰が、どのサブドメインでプラグインを利用しているのか」が特定できます。
一方、この仕組みでは「プラグインを何人のユーザーが利用しているのか」がわからないため、既存の有料プラグインは「サブドメインごとのライセンス」として利用を許可しているようです。

顧客管理もkintoneで

せっかくですから、顧客管理DBもkintoneアプリとして実装するのが手軽そうです。しかしそこで以下の2つが問題になります:

  1. ユーザーに顧客情報を入力させる方法

  2. プラグインから顧客管理アプリへの問い合わせ方法

既に自社のWebサイトがある場合は、そこにフォームを追加すれば問題1は解決します。しかしそのようなものが無かったらどうするでしょう。つまり、会社としてのWebサイトはあるけど、そのメンテナンスはたまにWebデザイン会社に発注するものであり、内部の人間がそこに自由にコンテンツを追加できない場合などです。
今回私たちは、Google Formに顧客情報入力フォームを作り、Google Apps Script(GAS)からkintone REST API経由で顧客管理アプリに情報を入力するように実装しました。また、GASではユーザーに対して自動的にメールを送信します。メールの本文には動的に生成したライセンスキーが含まれています。
問題2はもっと複雑です。単純に考えれば、プラグインから顧客管理アプリに通信すればよいはずですが、それはやりたくありません。これはkintoneプラグインというものが、ユーザーは絶対に改変できないサーバー側で動いているわけではなく、一度ファイルという形でダウンロードして、それをアプリにアップロードしており、そこでの悪意のある改変を防げないこと。また、プラグインから顧客管理アプリへの通信が、Webブラウザを通してユーザーに見えてしまいます。
ご存知のようにkintoneおよびプラグインは、サイボウズが用意したサーバーで実行されますが、プラグインから発する通信に関してはプラグインをインストールしたアプリ(サブドメインA)から顧客管理アプリが保存されている別のサブドメインBへのHTTPS通信としてクライアント側に表示されてしまいます。表示されるということは、そこで改変もできるということです。

外部サービスとkintoneとの連携については上記サイボウズの資料があります。内容をかいつまんで書くと、両者の間に中継サーバーを経由することで悪意のある改変や見せたくない情報漏洩を防ぐことを推奨しています。
ちなみに、プラグイン開発の資料を漁っていると割とすぐに見つかるサイボウズのドキュメントkintoneプラグイン開発入門 【Part2: 情報の隠匿方法編】ですが、私たちのケースには当てはまりません。あれは管理者権限を持ったユーザーがプラグインに対して設定した内容を、管理者権限のないユーザーに対して設定値を見せない方法です(参考URL)。私たちが想定するユーザーとは、自分でプラグインの設定画面に各種情報を入力するわけですから、隠しようがありません。
そのようなセキュリティに関する考慮をしつつ、今回私たちは以下の図のような顧客管理管理/ライセンス管理システムを設計しました。

ジャジャーン!

処理の流れ

ユーザーはnote記事のリンクから、Google Form上で必要な情報を記入します (1) 。フォームの送信ボタンを押すとGoogle Apps Script (GAS) が起動し、kintoneの顧客管理アプリへフォームの情報を送信します (2) 。ここではKintoneManagerというライブラリを利用しています。kintoneを呼び出す際、APIキーを渡すことでセキュリティを担保しています。同時に、GASからは顧客に対して、プラグインの保存場所を示したURLと、ライセンスキーが記載されたメールを送信しています。
ユーザーはメールに書かれたURLからプラグインをダウンロードし (4) 、プラグインをインストールしたいアプリにそれを組み込みます。また、設定画面からライセンスキーを入力します。
プラグインを起動すると、有効期限問い合わせ関数を呼びに行き (5)、その関数はkintoneの顧客管理アプリに更に問い合わせをします (6)。ここではGCFをJavaScriptで実装しており、KintoneRestAPIClientはAPI Token付きで問い合わせをします。
顧客管理アプリは関数に対して結果を返し (7) 、関数はプラグインに結果を返します (8) 。この結果が有効ならプラグインは起動、無効なら起動しません。

中継サーバーについて

サーバーといってもCloud Functionsは「サーバーレス」なのでこれは「言葉のあや」です。前にも少し触れましたが、プラグインから別のプラグインをAPI経由で呼ぶ場合、ユーザーの目に見える形でクエリ条件を書いてしまうと、結果として返ってくるレコードにはユーザーに見せたくないフィールドも入っていますし、クエリーのパラメータを改変することで他のユーザーの情報なども取得できることになってしまいます。
Cloud Functionsという中継サーバーをプラグインと顧客管理アプリの間に置くことで、ユーザーは関数の「入り口と出口」しか見えず、プラグインからは顧客管理アプリの構造、情報については知る手がかりはありません。プラグインから送信するのはライセンスキーとサブドメインだけで、返ってくる値は、そのライセンスが「有効か無効か」だけです。

悪意のあるユーザーが勝手に中継サーバーを立てて、常に「有効」を返したら?

それは困りますね。しかも、Webブラウザの開発者ツールを使えばJavaScriptの変数は自由に改変できます。Cloud Functions(GCF)へのURLを変数・定数として定義したらこのような「悪意のある中継サーバー」に誘導することは可能です。
では私たちはどうしたか?
URLは変数・定数としてではなく、"文字列リテラル"としてハードコーディングしました。これはエレガントではないですし力技ですが、有効です。その証拠に、例えばChromeなどの開発者ツールでJSコードを開いて、適当なところでブレークポイントを張って変数一覧を見て下さい。変数や定数が表示されて、それらは改変が可能ですが、文字列リテラルは変数リストに出てこないはずです。
もちろん、GCF側で不要なリクエストを弾く処理を実装しなければならないのですが、悪用されないために、実装方法をここではつまびらかにしません(概要くらいなら別記事に書くかもしれません)。

サーバーレスどころか(Web)サイトレス

今回はGoogleの各種サービスを使ってライセンス管理のシステムを構築しました。他社さんはどのように実装しているのでしょうね?おそらくAWSなどだと思いますが、Googleにした理由はまず一つは私はシンプルなのが好みだということと、Google Form、Google Apps Scriptの単純さに加えて、Cloud FunctionsもAWS Lambdaに比べて機能が少ない一方、簡単に扱うことができるという点で立ち上げ時には有利だと感じました。また、プラグインの保存場所もGoogle Driveです。GCPと無料のGoogleアカウントを両方利用しています。
この設計を、私は勝手に「(Web)サイトレス」と呼んでいます。サーバーレスどころか、Webサイトとしてnoteを利用することで、Webサイト管理に関する開発とは関係のない保守作業も省略することができました。古き良きWordPressなどを利用するとなると、(未だに同じかわかりませんが)プラグイン脆弱性のパッチ当て、ミドルウェアのバージョンアップ、OSやDBの管理などなど、Webサイト以外の工数が掛かってしまっていました。今回のプラグインの開発・公開のような少人数で立ち上げる場合では、そのような「実際の開発以外の手間」はなるべくかけたくないものです。

結論・正解のない環境で試行錯誤する

世の中に既に沢山ある有料プラグインでも、そのライセンス管理の実装はそれぞれ異なると思います。今回私たちが公開したのは無料プラグインなので、料金の徴収部分についてはここでは触れていません。しかしこれも技術的には解決可能ですし、Stripeを利用してnoteから販売するという「サイトレス」の設計にすることも可能かもしれません。
ヴィップシステムでは、現在公開中の2つの他にも複数のプラグインを開発中です。近いうちに皆さんにお見せできると思いますので、楽しみにしていて下さい。

お問い合わせ

kintone導入検討時のご相談から、導入後の利活用・定着化に至るまで、私たちは、お客様と「伴走」しながら思いを込めてサポートいたします。ご相談無料ですので、ぜひお気軽にお問い合わせください。

記事作成
kintone推進チーム
使用画像
UnsplashAlvaro Reyesが撮影した写真