🔍 拡張機能(Plugin)と認証
認証方式は web/auth-methods.json の control で 0〜7 の番号で指定します。デフォルトは 0(認証なし)で起動します。認証後、window.kasugaiAuth に認証情報がセットされ、その後 app.js と通常プラグインが起動します。.kasc は全方式で読み取り可能ですが、サーバーへの書き込み(KV/GCS への保存)ができるのは 3・4(cloudflare 系)と 5・6・7(cloudrun 系)のみです。0〜2 では「適用」はブラウザ内への反映のみで、「エクスポート(.kasc)」でのファイル運用になります。
⚠️ セキュリティ上の注意
「認証のみ」系の方式(3 Pages・5 cloudrun)は最低限の起動制御 + .kasc 設定情報の保護です。アプリの起動を制御し、.kasc の内容は ID/PASS 認証後に KV(Cloudflare)または GCS(Cloud Run)から取得されます。ただし、HTML/JS/CSS などの静的ファイル自体は公開されており、DATA/ 内の画像・GeoJSON 等は保護対象外です。auth-selector.js は auth-methods.json で選択された方式のみを読み込みます。完全なファイルアクセス制御が必要な場合は、4 Workers・6 cloudrun-gate・7 cloudrun-iap、または Cloudflare Access(Zero Trust)等でファイル配信を制御してください。
0. 認証なし(none)
ID/PASS 不要。誰でも起動可能。ローカル開発や非公開の信頼環境向け。
1. ローカル認証(local)
最小限のローカル向け認証。ID/PASS を平文で照合するテスト・実験用。
2. 簡易パスワード認証(password)
クラウド不要の JS 内ハッシュ比較。閉じた環境・テスト用途向け。
3. Cloudflare 認証(cloudflare)— Pages
サーバーレス ID/PASS 認証。.kasc は Cloudflare KV、秘匿データは r2:// で R2 認証ゲート経由。安全な本番運用に推奨。
4. Cloudflare 認証(cloudflare)— Workers
3 の機能に加え、静的ファイル自体も含めて全リクエストを認証ゲート。最も強い保護。
5. Cloud Run 認証(cloudrun)— 認証のみ
Cloud Run 版の ID/PASS 認証。.kasc は GCS、秘匿データは gs:// で署名付き URL 経由。静的は公開のまま。
6. Cloud Run 認証(cloudrun-gate)— 全ゲート
5 に加え、静的ファイルを含む全リクエストを kasugai_session Cookie でゲート。
7. Cloud Run 認証(cloudrun-iap)— IAP 委譲
Cloud IAP に認証を完全委譲。Google アカウントで全ファイルを保護。アプリ側コードほぼゼロ。
2つのサーバーレス基盤(Cloudflare 系 / Cloud Run 系)
サーバー側機能は Cloudflare(Pages Functions / Workers)と Google Cloud(Cloud Run)の2系統に対応しています。提供する API 契約(/api/auth・/api/kasc・/api/data/*・/api/gemini・/api/capabilities)は同一で、フロント側は /api/capabilities の応答(tier・features)だけを見て出し分けるため、どちらの基盤でも同じ web/ がそのまま動きます。違いは実行基盤・永続化・設定方法だけです。
| 項目 | Cloudflare 系(3 Pages / 4 Workers) | Cloud Run 系(5/6/7) |
|---|---|---|
| 実行基盤 | Pages Functions / Workers(エッジ・JS) | Cloud Run(コンテナ・FastAPI/Python) |
| 実装 | functions/+workers/worker.js(JS) | agent/(FastAPI) |
| .kasc 保存先 | KV(kasc:<id>) | GCS(kasc/<id>) |
| 秘匿データ | R2(r2://) | GCS(gs://・署名付き URL 302) |
| AI プロキシ POST /api/gemini | functions/api/gemini.js(サーバーキー注入・転送のみ) | agent/app/main.py(同一実装) |
| 外部エージェント POST /agent/chat | 両基盤ともサーバー側実装はなし(廃止)。外部実装を繋ぐ窓口はフロントの「エージェント」設定に常備 | |
| capabilities | {tier:"workers"} | {tier:"cloudrun"} |
| 認証ゲート | 3=APIのみ / 4=全リクエスト(Cookie) | 5=APIのみ / 6=全リクエスト(Cookie)/ 7=IAP 委譲 |
| 設定・秘密情報 | wrangler.toml+wrangler secret put | 環境変数+Secret Manager |
| Gemini キー保管 | サーバーキー: wrangler secret put GEMINI_API_KEY(暗号化・読み出し不可) | サーバーキー: 環境変数 or Secret Manager |
| デプロイ | python run-workers.py(または wrangler deploy) | docker build+gcloud run deploy(agent/README.md) |
POST /api/gemini は内蔵AI(ブラウザ)向けの薄いキー隠蔽プロキシです。ブラウザの generateContent リクエストにサーバーキー(GEMINI_API_KEY)を注入して転送するだけで、推論ループと地図操作はブラウザ側に留まります — BYO(Bring Your Own:各ユーザーがブラウザ localStorage に登録した自分の Gemini キー。サーバーには送られない)があればブラウザから直接 Gemini を呼び、無ければこのプロキシ経由でキーレス利用します。外部エージェントプロトコル({message,project,camera,layers,history,apiKey?} → {reply,actions,report})の送信窓口はフロントに常備しており、外部のエージェント実装があればエンドポイントURL設定で接続できます(サーバー側実装は廃止しました — 内蔵AIが本体のため)。レート制限は Cloud Run 側はプロセス内管理、Cloudflare 側は KV バインド時のみ有効です(ANTIGRAVITY_RATE_LIMIT)。
資産ごとの秘匿状況(認証方式別)
「ID/PASS」「設定ファイル(.kasc)」「実ファイル(アプリ本体・GISデータ)」が、方式ごとにどこまで秘匿されるかの一覧です。
| 資産 | 0 none | 1 local | 2 password | 3 Pages | 4 Workers | 5 cloudrun | 6 gate | 7 iap |
|---|---|---|---|---|---|---|---|---|
| ID/PASS | −(認証なし) | ❌ JS内に平文 | △ JS内ハッシュ 弱いPASSは解析可 |
✅ 環境変数のみ ブラウザへ送信されない |
✅ 同左 | ✅ Secret Manager ブラウザへ送信されない |
✅ 同左 | ✅ Google アカウント アプリは資格情報を持たない |
| .kasc 設定 | ❌ 全公開 | ❌ 全公開 | ❌ 全公開 | ◐ KV 内で秘匿 ログイン後は全量がブラウザへ配信 |
◐ 同左 | ◐ GCS 内で秘匿 ログイン後は全量がブラウザへ配信 |
◐ 同左 | ◐ IAP 内側 GCS 利用時は同左 |
| HTML/JS/CSS (アプリ本体) |
❌ 全公開 | ❌ 全公開 | ❌ 全公開 | ❌ 全公開 | ✅ 未ログインは 401 ログイン画面系のみ公開 |
❌ 全公開 | ✅ 未ログインは 401 ログイン画面系のみ公開 |
✅ IAP がリダイレクト |
| データ(web/) URL が公開情報から分かる |
❌ 列挙容易 | ❌ 列挙容易 | ❌ 列挙容易 | ◐ 対象は限定的 .kasc は KV で非公開のため、projects.json・HTML/JS・残置 .kasc 由来のみ |
✅ 未ログインは 401 | ◐ 対象は限定的 .kasc は GCS で非公開のため、projects.json・HTML/JS・残置 .kasc 由来のみ |
✅ 未ログインは 401 | ✅ IAP 内側 |
| データ(web/) URL が非公開・推測困難 |
△ obscurity | △ obscurity | △ obscurity | △ obscurity | ✅ 未ログインは 401 | △ obscurity | ✅ 未ログインは 401 | ✅ IAP 内側 |
| データ (R2・r2:// / GCS・gs:// 経由) |
− | − | − | ✅ トークン必須 未ログインは取得不可 |
✅ 同左 | ✅ トークン必須 署名 URL は期限付きベアラ |
✅ 同左 Cookie でも可 |
✅ IAP JWT / 署名 URL |
✅ 秘匿される ◐ 条件付きで秘匿 △ 弱い保護 ❌ 公開 − 該当なし
「web/ 静的配信」の2区分について:静的ファイルに認証チェックはなく、URL が分かれば誰でも取得できる点は同じです。違いは URL の発見可能性だけです。「URL が公開情報から分かる」とは、公開の .kasc・projects.json・HTML/JS 内にパスが書かれている、または projects/default/DATA/... のような推測しやすい固定パスのケース — 実質的に一覧・総当たりで列挙可能です。「URL が非公開・推測困難」はどこにもパスが書かれていないケースで、URL そのものが秘匿情報として機能します( obscurity による弱い隠蔽で、URL が一度漏れれば防御はゼロです)。方式3 で .kasc を KV に移せば、そこに書かれたデータ URL は未ログイン者には発見できなくなります。
共通の前提:「ログインした人」からは .kasc・データは見えます(ブラウザへ配信されるため)。秘匿が効くのは「未ログインの第三者」に対してです。方式3〜6 の署名トークンは /api/data/...?token=… の URL に現れるため、ログイン済みブラウザから読み取れば有効期間中(12時間)は KV/GCS にアクセス可能です。方式5/6 の署名付き URL も同様に期限付き(既定15分)のベアラ URL です。各方式の詳細はそれぞれのページを参照してください。
認証用ログインUI
ローカル認証(1)、パスワード認証(2)、Cloudflare 認証(3・4)、Cloud Run 認証(5・6)は、同じログインUIコンポーネント web/auth-login-form.js を使用します。画面の見た目・入力チェック・ローディング表示・エラー表示を共通化し、認証方式ごとの判定処理だけを web/PLUGIN/auth-*/auth.js に閉じ込めています。
新しい認証方式を追加する場合は、web/PLUGIN/<id>/auth.js から showLoginForm({ onSubmit }) を呼び出し、onSubmit コールバック内で独自の認証処理を記述してください。詳細は README.md を参照してください。
起動後通常プラグイン
機能拡張プラグインは web/PLUGIN/<plugin-id>/plugin.js に配置し、web/plugins.json に登録します。plugins.json は利用可能なプラグインのカタログで、既定では自動ロードされません。実際に起動するのは、プロジェクトの .kasc(インスペクタ)に plugin: <id> | key=value ... と宣言されたプラグイン、"auto": true を付けたエントリ、管理タブで有効化したストレージプラグインです。
web/PLUGIN/sample-hello/plugin.js
web/PLUGIN/auth-local/auth.js
plugin: 行で起動したプラグインはプロジェクトスコープとして扱われ、registerPluginLayer の scope は強制的に "project" になります(プロジェクト切替・行削除でレイヤー除去+registerPlugin の meta.dispose() が呼ばれ停止)。plugin: <id> | off は宣言解除や auto エントリ・有効なストレージプラグインのそのプロジェクトでの抑制に使えます。宣言できるのはカタログ/ストレージの ID のみで、外部 URL の直接指定はできません(共有 .kasc による任意コード読み込み防止)。
通常プラグインは window.kasugaiApi 経由で Cesium viewer やカメラ、レイヤー情報にアクセスできます。詳細は README.md を参照してください。
plugins.json に layer を宣言すると、本体がプラグイン専用レイヤーを自動登録し、レイヤ一覧・表示切替・属性検索・属性パネルの対象になります。format: "entities" は本体生成の DataSource に動的 entity を追加する方式、format: "geojson" は api.setPluginLayerData() で GeoJSON を渡して内蔵レイヤーと同じ描画経路で表示する方式です。scope: "project" でプロジェクト切替時に自動削除もできます。style: "QMLファイルのURL" を指定すると geojson 形式レイヤーに QGIS スタイル(単一・分類・ルールベース・ラベル)を適用できます(api.registerPluginLayer の style オプションと同じ)。