# 通知設計書 10-secure_input（セキュア入力通知）

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータにおけるセキュア入力（Secure Input）通知機能の設計について記述する。

### 本通知の処理概要

secure_input通知は、macOSのセキュアキーボード入力機能が有効であることをユーザーに視覚的に通知する機能である。セキュア入力はパスワード入力時などに自動的に有効化され、他のアプリケーションがキーボード入力を傍受することを防ぐ。

**業務上の目的・背景**：パスワードやSSHキーのパスフレーズなど、機密情報の入力時にセキュリティを確保する。セキュア入力が有効な間、キーロガーなどの悪意のあるソフトウェアからキーボード入力を保護する。ユーザーはオーバーレイアイコンにより、現在セキュアモードで入力中であることを視覚的に確認できる。

**通知の送信タイミング**：
- 自動：パスワードプロンプト検出時（OSC 133シェル統合など）
- 手動：ユーザーがメニューから「Secure Keyboard Entry」を有効化した時

**通知の受信者**：Ghosttyターミナルを使用しているmacOSユーザー。

**通知内容の概要**：ウィンドウ右上に鍵アイコン付きのオーバーレイを表示。タップすると説明ポップオーバーが表示される。

**期待されるアクション**：特別なアクションは不要。ユーザーはセキュア入力が有効であることを確認できる。

## 通知種別

アプリ内通知（ウィンドウオーバーレイ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（状態変更直後に即時表示） |
| 優先度 | 高（セキュリティ関連） |
| リトライ | 無し |

### 送信先決定ロジック

オーバーレイは、セキュア入力が有効なサーフェスを含むウィンドウに表示される。グローバルモードの場合はすべてのウィンドウに表示される。

## 通知テンプレート

### オーバーレイ通知

| 項目 | 内容 |
|-----|------|
| アイコン | lock.shield.fill（SFシンボル） |
| 位置 | ウィンドウ右上 |
| 背景 | グラデーションアニメーション（シアン/ブルー/イエロー） |
| タップ時 | 説明ポップオーバーを表示 |

### ポップオーバー説明文

```
Secure Input is active. Secure Input is a macOS security feature that
prevents applications from reading keyboard events. This is enabled
automatically whenever Ghostty detects a password prompt in the terminal,
or at all times if `Ghostty > Secure Keyboard Entry` is active.
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| enabled | Bool | 必須 | セキュア入力が有効かどうか |
| global | Bool | 必須 | グローバルモードかどうか |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | メニューから「Secure Keyboard Entry」選択 | macOS版 | グローバルモード切り替え |
| 自動検出 | パスワードプロンプト検出 | macOS版 | シェル統合による検出 |
| Surface状態変更 | secure_inputアクション実行 | macOS版 | サーフェスごとのスコープ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| Linux/GTK版 | この機能はmacOS版のみで利用可能 |
| アプリ非アクティブ | アプリがアクティブでない場合、セキュア入力は一時的に無効化される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[トリガー] --> B{トリガー種別}
    B -->|グローバル切り替え| C[SecureInput.shared.global = toggle]
    B -->|サーフェススコープ| D[SecureInput.setScoped]
    B -->|パスワード検出| D
    C --> E[apply関数呼び出し]
    D --> E
    E --> F{desired状態?}
    F -->|有効にしたい| G[EnableSecureEventInput]
    F -->|無効にしたい| H[DisableSecureEventInput]
    G --> I{成功?}
    H --> I
    I -->|成功| J[enabled状態更新]
    I -->|失敗| K[エラーログ出力]
    J --> L[@Published enabled変更]
    L --> M[SecureInputOverlay表示/非表示]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

| テーブル名 | 更新条件 | 更新内容 |
|-----------|---------|---------|
| UserDefaults | グローバルモード変更時 | "SecureInput"キーにBool値を保存 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| EnableSecureEventInput失敗 | Carbon API呼び出しエラー | 警告ログ出力、状態は変更しない |
| DisableSecureEventInput失敗 | Carbon API呼び出しエラー | 警告ログ出力、状態は変更しない |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### 状態保存

| 項目 | 内容 |
|-----|------|
| グローバルモード | UserDefaultsに保存、アプリ再起動時に復元 |
| スコープモード | メモリ内のみ、再起動で解除 |

### 配信時間帯

制限なし（24時間いつでも利用可能）

## セキュリティ考慮事項

- セキュア入力はmacOSのCarbon APIを使用し、他のアプリケーションがキーボードイベントを監視することを防ぐ
- アプリがアクティブでなくなった時は自動的にセキュア入力を解除し、再アクティブ時に再有効化する
- グローバルモードはユーザー設定として永続化され、アプリ再起動時に復元される
- 鍵アイコンオーバーレイにより、ユーザーはセキュアモードを視覚的に確認できる

## 備考

- macOS版のみで利用可能（Carbon API使用）
- EnableSecureEventInput/DisableSecureEventInputはCarbon APIの機能
- グローバルモードとスコープモードの両方をサポート
- スコープモードはフォーカス状態を追跡し、フォーカスがある間のみ有効
- GTK/Linux版では未実装（isActionSupportedOnGtkでfalseを返す）

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

セキュア入力に関連するアクション定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | action.zig | `src/apprt/action.zig` | SecureInput enum（行588-596）を確認 |
| 1-2 | action.zig | `src/apprt/action.zig` | secure_inputアクション定義（行246-251）を確認 |

**読解のコツ**: SecureInputはon/off/toggleの3値。アクションは状態変更を通知する。

#### Step 2: キーバインディングを理解する

toggle_secure_inputバインディングの定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Binding.zig | `src/input/Binding.zig` | toggle_secure_input定義（行722-727）を確認 |
| 2-2 | command.zig | `src/input/command.zig` | コマンドパレット定義（行636-640）を確認 |

#### Step 3: Surface処理を理解する

Surfaceでのsecure_inputアクション実行を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Surface.zig | `src/Surface.zig` | secure_inputアクション実行（行1372-1380）を確認 |
| 3-2 | Surface.zig | `src/Surface.zig` | toggle_secure_inputバインディング処理（行5726-5730）を確認 |

#### Step 4: macOS実装を理解する

macOSでのSecureInput実装を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SecureInput.swift | `macos/Sources/Features/Secure Input/SecureInput.swift` | SecureInputクラス全体を確認 |
| 4-2 | SecureInput.swift | `macos/Sources/Features/Secure Input/SecureInput.swift` | apply関数（行84-105）を確認 |
| 4-3 | SecureInput.swift | `macos/Sources/Features/Secure Input/SecureInput.swift` | onDidBecomeActive/onDidResignActive（行109-134）を確認 |
| 4-4 | SecureInputOverlay.swift | `macos/Sources/Features/Secure Input/SecureInputOverlay.swift` | オーバーレイUI実装を確認 |

**読解のコツ**: SecureInputはシングルトンパターン。globalプロパティでグローバルモード、scoped辞書でサーフェスごとのスコープを管理。desired計算プロパティでどちらかが有効なら全体が有効になる。

#### Step 5: AppDelegateでの統合を理解する

AppDelegateでのSecureInput管理を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | AppDelegate.swift | `macos/Sources/App/macOS/AppDelegate.swift` | 起動時の復元処理（行198-201）を確認 |
| 5-2 | AppDelegate.swift | `macos/Sources/App/macOS/AppDelegate.swift` | setSecureInput関数（行1046-1060）を確認 |
| 5-3 | AppDelegate.swift | `macos/Sources/App/macOS/AppDelegate.swift` | toggleSecureInput IBAction（行1102-1104）を確認 |

#### Step 6: GTK/Linux での非対応を確認

GTK版では未実装であることを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | application.zig | `src/apprt/gtk/class/application.zig` | secure_input未実装（行765）を確認 |
| 6-2 | command_palette.zig | `src/apprt/gtk/class/command_palette.zig` | GTKでの非サポート（行213）を確認 |

### プログラム呼び出し階層図

```
secure_inputトリガー
    |
    ├─ グローバル切り替え: メニューから「Secure Keyboard Entry」
    |       |
    |       v
    |   AppDelegate.toggleSecureInput() (AppDelegate.swift:1102)
    |       |
    |       v
    |   AppDelegate.setSecureInput(.toggle) (AppDelegate.swift:1046)
    |       |
    |       v
    |   SecureInput.shared.global.toggle()
    |
    └─ サーフェススコープ: パスワードプロンプト検出
            |
            v
        Surface.performBindingAction(.toggle_secure_input) (Surface.zig:5726)
            |
            v
        rt_app.performAction(.secure_input, .toggle)
            |
            v
        macOS: Ghostty.setSecureInput()
            |
            v
        SecureInput.setScoped() または SecureInput.shared.global
            |
            v
        SecureInput.apply() (SecureInput.swift:84)
            |
            ├─ enabled -> DisableSecureEventInput()
            |
            └─ !enabled -> EnableSecureEventInput()
                    |
                    v
                enabled = desired
                    |
                    v
                @Published enabled変更
                    |
                    v
                SecureInputOverlay表示/非表示
```

### データフロー図

```
[入力]                      [処理]                         [出力]

ユーザー操作/自動  ───▶  secure_inputアクション     ───▶  SecureInput状態変更
                              |
                              v
                         SecureInput.apply()
                              |
                              v
                         EnableSecureEventInput()
                         または
                         DisableSecureEventInput()
                              |
                              v
                         @Published enabled
                              |
                              v
                         SecureInputOverlay
                              |
                              v
                         鍵アイコン表示/非表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| action.zig | `src/apprt/action.zig` | ソース | SecureInput enum、secure_inputアクション |
| Binding.zig | `src/input/Binding.zig` | ソース | toggle_secure_inputバインディング |
| command.zig | `src/input/command.zig` | ソース | コマンドパレット定義 |
| Surface.zig | `src/Surface.zig` | ソース | secure_inputアクション実行 |
| SecureInput.swift | `macos/Sources/Features/Secure Input/SecureInput.swift` | ソース | SecureInputクラス、Carbon API呼び出し |
| SecureInputOverlay.swift | `macos/Sources/Features/Secure Input/SecureInputOverlay.swift` | ソース | オーバーレイUI |
| AppDelegate.swift | `macos/Sources/App/macOS/AppDelegate.swift` | ソース | macOSアプリデリゲート、setSecureInput |
| application.zig | `src/apprt/gtk/class/application.zig` | ソース | GTK版（未実装） |
| command_palette.zig | `src/apprt/gtk/class/command_palette.zig` | ソース | GTK非サポート定義 |
