Skip to content

v0.36.0

Choose a tag to compare

@github-actions github-actions released this 18 Sep 08:42
· 25 commits to main since this release
Immutable release. Only release title and notes can be modified.
eb92eba

sshc v0.36.0

v0.36.0では、2026年9月18日に行った仕様・実装・セキュリティの監査で見つかった問題をまとめて修正しました。ブラウザー登録の仕組みを作り直し、CLIがengineを確かめてから秘密情報を渡すようにし、SSH設定の解決をOpenSSHと同じ規則に揃えています。SFTPでは、サーバーが返す不正な名前の拒否、別ホストへの移動での削除前の照合、ダウンロードの速度低下の解消を行いました。

あわせて、SFTPのタブをドラッグしてペインを分ける操作、シンボリックリンクの解決、Terminalの再接続時の画面サイズの反映、削除前の確認ダイアログの統一、英語UIの用語の統一を行っています。

更新後に必要な操作

  • ブラウザーの登録を一度やり直してください。 登録情報の保存形式が変わり、v0.35.0以前の登録は読み込みません。更新後にengineを再起動し、sshc(またはsshc open)が表示するURLをブラウザーで開くと登録し直せます。
  • engineを再起動してください。 新しいCLIは、engineが引き継ぎ用の秘密を持っていることを確かめてからstatusvaultの操作を行います。更新前から動き続けているengineに対しては、engineを確認できない旨のエラー(did not prove it holds the handoff secret)になります。

ブラウザー登録とCLIの安全境界

  • これまでブラウザーの登録トークンは一度発行すると変わりませんでしたが、ブラウザーが登録情報で入り直すたび(engineの再起動後や、新しいタブでsshcを開いたとき)に新しいトークンへ差し替えるようにしました。差し替え前のトークンは、同じブラウザーの別タブのために1分間だけ同じ新しいトークンを返します。それを過ぎて古いトークンが提示された場合は複製とみなし、その登録を失効させます。
  • 登録は最後に使ってから30日で失効します。engineが使うポートが変わった場合も、以前のポート向けの登録はすべて失効します。登録できるブラウザーは16件までで、古いものから消えます。
  • engine側が保存するのは、照合用のハッシュ、発行と最終使用の時刻、ポート番号だけです。トークンそのものはワークスペースにも同期スナップショットにも含めません。
  • CLI(sshc statussshc vaultなど)は、引き継ぎ用の秘密を送る前に、engineへ乱数を送って秘密で署名した応答を検証します。engineが後始末を経ずに消え、同じポートを別のプロセスが占有していても、そのプロセスにマスターパスワードやS3の認証情報を渡しません。端末を閉じたときのSIGHUPでも通常の終了と同じ後始末を行い、引き継ぎ情報を残しません。
  • Webは、登録の回復が401で拒否された場合に保存済みトークンを捨て、再読み込みのたびに同じ拒否を繰り返さないようにしました。使用済みの初回URLを開いた場合も、登録済みのブラウザーならそのまま入れます。

SSH設定の解決

  • Match hostは、OpenSSHと同じくaliasではなく解決後のHostNameと比較するようになりました。これまではMatch host <alias>がaliasに一致していましたが、HostNameを別に書いている設定では一致しなくなります。OpenSSHのssh -Gと同じ結果になるように、Match hostにはHostNameを書いてください。
  • ProxyJumpProxyCommandの両方が解決された設定は、これまで接続を拒否していましたが、OpenSSHと同じく先に書かれた方だけを使い、後から来た行を無視するように変更しました。無視した行はConnectionsのAnalysisと保存前のプレビューに「無視された設定」として表示します。ProxyCommand noneの後のProxyJumpは無視され、ProxyJump noneの後のProxyCommandは有効です。
  • known_hosts!pattern(否定)をOpenSSHと同じように解釈します。

SFTP

  • タブのドラッグでペインを分割・結合できるようにしました。「2ペイン」ボタンは廃止し、Terminalと同じくタブをファイル一覧へドラッグすると左右2ペインに分かれます。ペインが1つならタブを落とした側に新しいペインを開き、元のペインには空のタブを残します。ペインが2つならもう一方へタブが移り、最後のタブが出て行ったペインは閉じます。境目のつまみで幅を変えられ、キーボードでは選択中のタブをShift+←/→で移せます。
  • シンボリックリンクは一覧でリンク先と種類を解決し、「名前 → リンク先」で表示します。ディレクトリへのリンクはフォルダーとして開き、ファイルへのリンクは詳細・プレビュー・編集・ダウンロードがリンク先を扱います。保存はリンク先を書き換えてリンクを残します。壊れたリンクとループは開けません。コピー・移動・削除・engineとの転送は従来どおりリンクを辿りません。
  • 一覧と比較ダイアログのサイズ表記をKiB/MiB/GiBにし、列名をSizeにしました。
  • ドロップの扱いを整理しました。同じ接続先の同じディレクトリへ落としても何もしません。同じ接続先の別のディレクトリへ落とした場合はダイアログを出さずに移動します。別ホストへ落とした場合は従来どおりコピー/移動を選びます。
  • 別のウィンドウやページからのドラッグは受け付けなくなりました。これまでは、別のページがsshcの行を装ったデータをドラッグに載せると、ペインへ落とした時点で確認なしにengineの転送が並ぶ可能性がありました。行の実体はページ内に置き、ドラッグには不透明な識別子だけを載せます。
  • 2ペイン表示で各ペインが狭くなると、一覧がスマホ向けの高い行に切り替わっていた問題を直しました。マウス操作のデスクトップでは1行の密な一覧(名前・サイズ・日付)を使い、タッチ端末だけ従来の高い行を残します。
  • ダウンロードの速度: 受信したデータの塊ごとに保存先のファイルを閉じ直してengineへ位置を報告していたため、ファイルサイズの二乗に比例して遅くなっていました(17 MiBで約15秒)。8 MiBごと、終了時、再試行の前だけ報告するように変更しました。切断時は届いた分を報告してから再試行します。
  • engine側のコピー/移動で「上書き」ボタンが何もしなかった問題を直しました。ファイルを失ったアップロードだけを再添付待ちとして扱います。
  • サーバーが返す不正な名前を拒否します。壊れた、または悪意のあるSFTPサーバーが一覧に../を含む名前を返した場合、これまではホスト間のディレクトリコピーだけが検証を持たず、信頼している別のサーバーの任意のパスへ書き込める可能性がありました。空、.../、NULを含む名前が返された一覧は全体をエラーにします。engine側のディスクへ書く場合は\も拒否します。
  • 別ホストへの移動は、コピー直後の状態と一致したファイルだけを削除するようにしました。コピー後に書き換えられた元のファイルを、転送しないまま消しません。
  • 新しくアップロードしたファイルの公開は、検証後に別のクライアントが同名のファイルを作っていた場合、上書きせず競合として失敗します。
  • 2分を超えるディレクトリ走査を伴うengine側のジョブが「中断」扱いにされていた問題を直しました。
  • 転送一覧が古い応答で上書きされ、開始直後のジョブが待機中に戻ってしまう問題を直しました。
  • Terminalからのリンクで開いたファイルのDownload/Editが、ペインがengine側のディスクを表示中は無反応だった問題を直しました。
  • テキストエディターは保存中に編集できないようにし、保存中の入力が保存結果で消えないようにしました。
  • 128文字を超えるパスの削除と権限変更がブラウザーからエラーになっていた問題を直しました。
  • 転送キューの保存ファイルは、シンボリックリンクを辿らず、上限付きで読み込み、一時ファイル経由で書き込むようにしました。壊れたキューは別名で残します。

Terminal

  • 再接続したセッションを、セッション開始時ではなくブラウザーの最新のサイズで開くようにしました。再接続を待っている間にウィンドウやサイドバーの幅を変えた場合も反映します。これまでは再接続後の行数・列数が表示とずれ、リモートのプログラムが見えない行へ描くことがありました。
  • 再接続の握手中に「再接続を止める」を押すと、接続に成功しても入力が届かず手動の再接続もできなくなる問題を直しました。
  • サーバーが応答しない場合の検出を直しました。keepaliveの応答待ちに期限がなく、ServerAliveCountMaxが効いていませんでしたが、OpenSSHと同じく間隔内に応答がなければ1回の失敗として数えます。
  • ポート転送で、書き終えてから応答を待つクライアントの応答が落ちることがあった問題を直しました。ForwardAgentのソケットが接続ごとに残っていた問題も直しています。
  • kitty形式(OSC 99)の分割された通知を上限なく連結していたため、悪意のあるサーバーの出力でengineのメモリが増え続ける可能性がありました。配信する上限で打ち切ります。
  • keyboard-interactive認証の表示文からは制御文字を取り除きます。
  • Terminal設定の保存時に、範囲外の値(verbosity、再接続回数、背景の濃さ、配色など)を拒否するようにしました。これまでは保存されてしまい、以後Settingsとショートカットの同期が読み込みに失敗していました。列数・行数は1〜1000の範囲で受け付けます。

削除前の確認と画面の統一

  • Vaultの資格情報(専用鍵のパスフレーズの解除を含む)、スニペット、保存したWorkspaceレイアウトは、これまで確認なしに削除していましたが、他の削除と同じ確認ダイアログを出すようにしました。キーボードショートカットのプリセットの確認も同じダイアログになります。
  • 保存したWorkspaceレイアウトの削除に失敗した場合、これまでは何も表示していませんでしたが、他の操作と同じく画面にエラーを出します。
  • 英語UIで同じ画面に「console」と「session」が混在していたのを、日本語と同じく開いているものは「session」、画面や外観は「terminal」に統一しました。
  • パネル直下のエラー表示の色と余白を統一しました。
  • ロック画面の言語選択は、Menuと同じ表記を使います。

Sync

  • 自動同期の失敗理由と、手動のPull/Pushの失敗理由が、同じ原因でも別の名前で表示されることがあった問題を直しました。
  • Vaultが存在しない状態でSyncの設定を変更した場合に、サーバーエラーではなくVaultがロック中のときと同じ扱いにします。

ドキュメント

  • 接続時に自動実行するスニペットの説明を実装に揃え、複数ホストでの実行を「コマンド」ページに書きました。
  • pagesとdocsの記述を実装に合わせて直し、書かれていなかった機能を追加しました。

内部の変更

  • Web(非同期操作の状態、ブラウザーの保存、定期取得、JSONを送るAPI呼び出し、サイズと日時の整形、ホスト検索)とengine(remotesyncの失敗分類、CLIのengine状態取得、systemd/launchdのservice管理、SFTPエントリの変換)で、同じ処理の重複を1つの実装にまとめました。動作は変えていません。
  • APIの契約(api/openapi.yaml)と実装の食い違いを揃えました。確認トークンが必要な操作にX-SSHC-Actionヘッダーを宣言し、aliasの上限を64文字に統一しています。

更新後

Webではバイナリ更新後に稼働中のengineを再起動し、sshc(またはsshc open)のURLからブラウザーを登録し直してください。Androidでは正式版APKを更新してください。

変更履歴: v0.35.0...v0.36.0