Reality BridgeHow-toFor adminsApplies from 4.2.5
SSH connector
Cette page en françaisThis page on the GitHub wiki
The SSH connector opens a virtual terminal over SSH: a player logs in with the pairing code their game shows as the
password (or with a public key the operator declared for them), then types the commands the game declares, and reads
the files of the game's virtual disk with ls, cd and cat. Nothing typed is ever run: there is no shell behind
it. It is experimental, like every connector (Connectors overview).
What you get
A quest-n-click-connector ssh process listening on a port with its own host key, answering the commands of
reality.connectors.ssh and showing its files, and proposing the commands' signals for the player who logged in.
Unlike Telnet, what is typed is encrypted on the way.
Context and versions
- A connector beside a running Bridge, from 4.1.9; this page applies from 4.2.5 (the
quest-n-click-connectorname). ssh2(pure JavaScript, MIT) carries the protocol; its optional native parts are refused (connectors/vendor/).- Verified on: not replayed for this page. CI plays it from the release archive (
npm run connector-archive-e2e: the pairing code as password, the commands, a file of the virtual disk) and under floods intests/connectors-ssh.test.ts; no person has yet run it on a network.
Prerequisites
-
A running Bridge (Install and run the Bridge) and a game whose
reality.connectors.sshdeclares its commands and files (Signals and the manifest):ssh: { prompt: 'shed$ ', commands: [{ says: 'lamp on', reply: 'Click.', signal: 'terminal.lamp' }], files: { '/notes/lamp.txt': 'The lamp obeys two words: lamp on.' }, } -
ssh-keygen, to make the connector's host key.
Where to run the commands
grant where the Bridge's folder is; the connector on the machine players connect to, in a folder holding its
configuration, token and host key (mode 600). npm run connector -- ssh … in the engine repository,
npx quest-n-click-connector ssh … with the package.
Steps
-
Grant the connector its token, with pairing:
# in the engine repository (the Bridge's folder is .cache/bridge) npm run bridge -- grant --connector=shed-ssh --source=terminal --signals=terminal.lamp --pair > ssh.token
-
Make the connector's host key:
# in the connector's folder ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N ''
-
Write its configuration,
ssh.json.keysis optional: a public key per player, for players who would rather not type a code:{ "bridge": { "url": "http://127.0.0.1:8787/", "tokenFile": "ssh.token" }, "gameId": "signals", "health": { "port": 9303 }, "ssh": { "port": 2222, "hostKeyFile": "ssh_host_ed25519_key", "keys": [{ "key": "ssh-ed25519 AAAA…", "playerId": "p-0123456789abcdef" }] } }
-
Start it:
# in the engine repository npm run connector -- ssh --config ssh.json
-
Log in as a player would; the user name does not matter, the password is the code the game shows:
# on a machine that reaches the port ssh -p 2222 player@127.0.0.1After the banner,
lamp onprints the command's reply and proposesterminal.lamp;ls /notesandcat /notes/lamp.txtread the virtual disk.
Expected result, and how to check it
GET http://127.0.0.1:9303/healthanswers 200;GET /metricscounts proposals and refusals.- The Bridge logs
"event":"pairing.confirmed"(for a password login with a code), then"event":"signal.accepted".
Common errors
| Symptom | Cause | Fix |
|---|---|---|
ssh: "hostKeyFile" names the host key at start | No host key in the configuration | Step 2, then hostKeyFile |
Permission denied, then the connection closes | A wrong or expired code, a resume word past its 30 minutes, or an undeclared key, three times | A new code from the game |
| The connection is refused at once | Six wrong passwords from that address in ten minutes, across reconnections; 3 connections already open from it, or 20 in all | Wait |
A command given on the ssh line, sftp, scp or a forwarding is refused | Only an interactive terminal opens | Log in without a command |
| The connection closes | Not authenticated within 20 seconds; authenticated without opening a shell for a minute | Open the terminal at once |
Files or data changed
None on disk. Resume words live in memory for 30 minutes; nothing typed is stored.
Recovery or going back
Stop the process (SIGTERM). A player's declared key is removed from ssh.keys, then the connector restarted. If the
connector's token leaked, revoke it on the Bridge and grant a new one; if its host key leaked, make a new one (players'
SSH clients will warn that the host key changed).
Reference: what the terminal does
ssh: { "port", "host" (127.0.0.1), "hostKeyFile", "keys"?, "limits"? }.- The password is a pairing code or a resume word (three tries per connection); or a public key the operator declared
for a player (
keys). - Only a terminal opens: the game's commands,
help,clear,exit, andls,cd,pwd,caton the game's virtual disk (files).exec,sftp(any subsystem), environment, agent, X11 and forwarding are refused. One session with one shell per connection. - Paths never leave the virtual tree, nothing typed is interpreted. The output wraps at the terminal's width (10 to 500 columns, 80 by default).
- The same limits as Telnet (a line of 512 bytes, 100 lines a minute, 64 KB a second received, 20 seconds to log in,
a minute between lines, 30 minutes a session, 3 connections per address and 20 in all, 6 wrong passwords per address
in 10 minutes), each overridable in
limitsby its name (Telnet). - Each line typed is a new fact: its key is
sha256('ssh:' + session + ':' + line number).
What it keeps
Nothing typed is stored: a line is matched against the game's commands and forgotten; the Bridge receives only the signal's name. A resume word links a later session to the same player for 30 minutes, in memory. The public keys an operator declares for players live in the connector's configuration until the operator removes them. The client's address is used for the connection and counted in memory for the limits; the connector keeps no list of them.
References
- The code:
connectors/src/ssh/connector.ts,connectors/src/terminal/. - The threat model:
docs/dev/threat-models/ssh.md. - Tested by
tests/connectors-ssh.test.ts.