iPhone・iPad向けSSHクライアント「Waterm」で、ServerとSnippetの保存機能を実装し、公式SwiftNIO SSHを使った接続検証を進めた。この記事は2026年10月2日までの開発記録をもとに、アプリ側の実装と独立した検証環境での成果をまとめたものである。
黒い空画面を直し、iOS 26を開発対象にする
前回は、Servers、Snippets、Settingsのタブを切り替えられるものの、主コンテンツが黒い空白だった。原因は各Viewが黒背景だけを返していたことだった。日本語の見出しと説明を持つContentUnavailableViewへ置き換え、String Catalogへ文言を追加した。
修正後はiPhone・iPad Simulatorで表示とタブ遷移を確認し、文字の切れ・重なり・クラッシュがないことを確認した。Debug/Releaseの署名なしビルドも成功している。その後、開発方針に合わせて最低OSをiOS / iPadOS 26.0へ変更した。前回の記事にあるiOS 17は当時の設定である。
SwiftDataとKeychainで保存する情報を分ける
アプリにはSchema V1とローカルのSwiftData containerを追加し、Serverの一覧、追加、編集、削除を実装した。フォームはDraftを編集し、検証してから保存する。保存失敗時に入力内容を保持する構造にしている。
秘密情報の保存境界にはCredentialStoreを設け、Keychain操作をactorにまとめた。PasswordとPrivate Keyのpayloadはversionを持ち、アクセス条件はWhenUnlockedThisDeviceOnly、同期は無効とした。通常のServer情報と秘密情報を分ける基盤はできたが、鍵importや認証情報の保存を含むフォーム連携は後続の作業である。
Snippetも一覧、追加、編集、削除に対応した。コマンド本文を勝手に改変せず、空白だけの入力、16 KiBを超える内容、改行や制御文字を拒否する。秘密を保存しないための注意文も表示する。Terminalへの安全な挿入と送信前編集は、まだ実装していない。
この段階ではSwift Testingの29件が成功した。Serverの追加・編集・再表示後の永続化・削除はiPhone Simulatorで確認している。
CitadelのiOS PTY API不適合を確認する
SSHの第一候補だったCitadel 0.12.1を調査すると、公開対話APIのwithPTYなどがmacOS専用になっていた。PackageがiOSを対象に含めていても、Watermが必要とする対話Shell、双方向のbytes、リサイズをiOSで利用できるとは限らない。最低OSを26へ上げても、この不適合は解消しなかった。
そこで公式SwiftNIO SSHとNIOTransportServicesを使う候補を、アプリから独立したTools/SSHProbeで検証した。検証時の固定版はswift-nio-ssh 0.15.0、swift-nio 2.103.0、NIOTransportServices 1.28.0、swift-crypto 4.5.2である。iOSではリモート側のPTYを使い、TCP接続にはNetwork.framework向けの経路を用いる。
Host Key承認前に認証しないことを確かめる
使い捨てのOpenSSH 10.0p2環境に対し、統合52チェックがすべて成功した。Host Keyが未一致・未回答のときに認証要求がゼロであることは、クライアント側の記録とsshdログの両方で確認した。承認後の認証に加え、PTY、リサイズ、UTF-8往復、Ctrl-C、終了状態、切断・取消、応答停止の検出も試している。
受信側の消費を止めるバックプレッシャー試験では、16 MiBのデータに欠落がないことを確認した。検証用ライブラリのgeneric iOSビルドに成功し、iOS 26.0のiPhone・iPad SimulatorでもPassword認証、Passphrase付きEd25519認証、Host Key拒否の実接続テストが成功している。
鍵形式の結果は、次のように分けている。
| 鍵形式 | 検証結果 |
|---|---|
| OpenSSH形式のEd25519、ECDSA P-256 | 平文・Passphrase付きとも実Server認証成功 |
| ECDSA P-384 / P-521 | 鍵読込成功、実Server認証は未検証 |
| RSA、PEM / PKCS#8、aes256-gcm暗号化鍵など | 現検証実装では未対応、明示拒否 |
接続検証の成功からアプリ内Terminalへ進む前に
SwiftNIO SSH候補の実証は進んだが、採用判断は保留中である。RSAをMVPの対象外とするか、自前のOpenSSH鍵parserとbcrypt_pbkdfを採用するか、Host Keyのユーザー承認待ちをtimeoutからどう分けるかが残っている。
SSH依存はアプリtargetへまだ追加していない。アプリ内SSH接続、Host Key管理、Terminal表示、補助キーは未実装で、実機の接続確認も未実施である。次はSwiftTermの固定版を決め、日本語IME、UTF-8分割、ANSI、リサイズ、制御キー、paste、scrollback上限を独立fixtureで検証する。