Skip to content

Latest commit

 

History

172 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PAssist(単一ウィンドウ・リモート操作)

このPCで開いている 任意のウィンドウを 1 つだけ 選び、URL を発行して、離れた第三者が ブラウザだけ・アカウント不要 で一時的に閲覧/操作できるアプリです。 デスクトップ全体は決して共有されません(キャプチャ元に画面全体を一切列挙しない設計)。

構成

remote_app/
├─ host/      Electron 製ホストアプリ(このPCで動かす)
│  ├─ main.js        ウィンドウ列挙・キャプチャ・入力注入の橋渡し・サーバ自動起動
│  ├─ input.js       nut.js による入力注入(座標クランプ+危険キーのブロック)
│  ├─ preload.js     レンダラへ最小APIを公開
│  └─ renderer/      ウィンドウ選択UI・WebRTC offer 側
└─ server/    シグナリング+中継+ビューア配信(Node)
   ├─ server.js
   └─ public/        ブラウザ用ビューア(WebRTC answer 側・入力送出)
  • 映像: WebRTC で配信 / 遠隔入力: DataChannel で送信
  • アクセス制御(既定): URLトークン + 有効期限(30分) + ホスト承認

必要環境

  • Windows 10/11
  • Node.js 18+(確認: v24 系)

セットアップ

# リポジトリ直下で(host と server の依存を両方入れます)
npm install

入力注入(遠隔操作)について: 多くの場合 npm install だけで有効になります(Electron 42 + nut.js 4 で動作確認済み)。起動時にホスト画面へ「⚠ 入力注入が無効(閲覧のみ)」と出た場合のみ、 ネイティブモジュールを Electron 用に再ビルドしてください:

npm run rebuild

再ビルドには Windows の C++ ビルドツール(Visual Studio Build Tools 等)が必要なことがあります。 再ビルドしない場合でも起動はでき、その場合は 閲覧のみ(操作不可)になります。

実行(同一LAN)

npm start
  • ホストアプリが起動し、内部でシグナリングサーバ(既定 :8443)も自動起動します。
  • ウィンドウを 1 つ選ぶと 共有URL が表示されます。
  • 第三者はそのURLをブラウザで開くだけ。ホスト側に「許可しますか?」が出たら 許可 で開始。
  • 同一LAN内ならこのまま動作します(URLは http://<このPCのLAN IP>:8443/s/...)。

実行(インターネット越し・UPnP 自動公開)

このPCが 公開IP を持ち、ルーターの UPnP が有効 なら、追加設定なしでインターネット公開できます。 npm start 時にアプリが UPnP で Web ポート(TCP 8443)を自動開放 し、公開IP付きの共有URL (http://<公開IP>:8443/s/...)を発行します。第三者は ブラウザでそのURLを開くだけ(インストール不要)。

npm start
# 起動ログに「[host] インターネット公開: http://<公開IP>:8443 ...」が出れば成功
  • 公開したくない(同一LAN内だけ): $env:PASSIST_PUBLIC="0"; npm start
  • UPnP が無効/多段NATなら、自動で 同一LAN内のみ にフォールバックします(ログに警告)。
  • 映像/操作は WebRTC で P2P(STUN)。厳しい NAT の相手とは繋がらないことがあり、その場合は TURN サーバ(coturn 等) を host/renderer/renderer.js・server/public/viewer.js の iceServers に追加してください(多人数運用なら中継サーバ集約型を推奨)。

https にしたいとき

http://<公開IP> のままでも 映像・操作は常に暗号化(WebRTC DTLS-SRTP)されます。ページ配信とシグナリング (トークン/PIN/信頼secret)も暗号化したい場合は次のいずれか:

  • Cloudflare トンネル(最も簡単・無料の正規証明書):
    cloudflared tunnel --url http://localhost:8443
    # 得られた https://xxxx.trycloudflare.com を、ホスト画面「外部公開URL」欄に入れて再発行
    # (この場合は UPnP もポート開けも不要。$env:PASSIST_PUBLIC="0" でOK)
  • 独自証明書: TLS_CERT/TLS_KEY を渡すとサーバが https/wss で待ち受け (生IPの証明書は取りにくいので、独自ドメイン+Let's Encrypt 推奨):
    $env:TLS_CERT="C:\path\cert.pem"; $env:TLS_KEY="C:\path\key.pem"; npm start

セキュリティ設計

要件 実装
ウィンドウだけ・デスクトップ全体は出さない キャプチャ元に screen を一切列挙せず window のみ。選択IDに固定。
アカウント不要 ビューアはURLのトークンのみで接続。ログインなし。
一時利用 セッションに有効期限(既定30分)。期限切れで自動失効。
勝手に繋がせない 既定でホスト承認制。ホストが「許可」するまで映像は流れない。
操作範囲をウィンドウ内に限定 入力座標を対象ウィンドウ矩形にクランプ。
デスクトップへ脱出させない Win / Alt+Tab / Alt+F4 / Ctrl+Esc / タスクマネージャ 等をブロック。

アクセス制御モードの切替(環境変数 ACCESS_MODE)

  • approve(既定): ホスト承認制
  • pin: 6桁ワンタイムPINを併用(ホスト画面に表示、口頭等で共有)
  • token: URLを知っていれば即接続(最も手軽・拡散注意)
$env:ACCESS_MODE = "pin"; npm start

その他: PORT(既定8443) / SESSION_TTL_MS(既定1800000) / PUBLIC_BASE_URL / REMOTE_SERVER_URL。

事前承認(信頼済み端末)

「一度認証した相手」や「事前に許可した相手」は、ホストが毎回「許可」を押さなくても自動接続できます。 アカウントは不要で、端末ごとの信頼クレデンシャル(clientId+secret)で実現します。

  • 方法A: 承認時に信頼する … 承認ダイアログの「この端末を信頼」にチェックして許可。 以後その端末(ブラウザ)は承認なしで接続できます。
  • 方法B: 事前に信頼リンクを発行 … ホスト画面の「信頼リンクを発行(事前承認)」で、 クレデンシャル入りURL(…/s/<token>#k=<clientId>.<secret>)を発行して相手に渡します。 相手は初回から承認不要で接続できます。

仕組み: 信頼クレデンシャルはホスト側(userData/passist-trust.json、secret はハッシュで保存)にのみ 永続化されます。ビューアは secret を localStorage に保存し、接続時に提示。ホストが照合して一致すれば ダイアログを出さずに自動承認します。secret 平文はビューア↔ホスト間でシグナリング経由で渡るため、 インターネット越しで信頼機能を使うなら https/wss(Cloudflareトンネル等)を推奨です。信頼の取り消しはホスト画面の「すべて解除」から。

テスト

# 信頼ロジックの単体テスト(ネットワーク不要)
npm test

# シグナリング/中継の結合テスト(先に approve モードでサーバ起動が必要)
#   ターミナル1:
$env:PORT="8990"; $env:ACCESS_MODE="approve"; node server/server.js
#   ターミナル2:
$env:TEST_PORT="8990"; npm run test:signaling

既知の制限(MVP)

  • 入力注入は OS レベルの実入力です(ホスト側の実カーソルが動きます)。対象ウィンドウが 他ウィンドウに隠れていると、重なった別ウィンドウに入力が当たる可能性があります。 対策として操作開始時に対象ウィンドウを自動で前面化します(nut.js の focus())。 ただしホスト側で別ウィンドウを手前にすると入力がずれるため、操作中は触らない運用を推奨。
  • ウィンドウの特定は HWND(ウィンドウハンドル)で厳密一致します(desktopCapturer の window:<HWND>:0 を利用)。同名ウィンドウが複数あっても取り違えず、タイトルの文字コードにも 依存しません(取得できない場合のみタイトル一致にフォールバック)。
  • 同時接続は1セッション1ビューア。
  • WebRTC のため厳しい NAT では TURN 必須。

Releases

Packages

Contributors

Languages