cmux-ssh-here 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin.js +21 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,3 +39,4 @@ Open the link — cmux connects on its own. `Ctrl-C` in the terminal stops the s
|
|
|
39
39
|
## Options
|
|
40
40
|
|
|
41
41
|
- `PORT=2222 npx cmux-ssh-here` — fixed port (random free port by default).
|
|
42
|
+
- `CMUX_SSH_DEBUG=1 npx cmux-ssh-here` — log incoming auth/env/exec/shell requests to stderr (troubleshooting).
|
package/bin.js
CHANGED
|
@@ -21,7 +21,9 @@ if (process.platform !== "win32") {
|
|
|
21
21
|
}
|
|
22
22
|
const { default: pty } = await import("node-pty");
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// ponytail: hex (not base64url) — cmux rejects a user that starts with "-",
|
|
25
|
+
// and an ssh client treats a leading-dash username as a flag. Hex is URL/ssh-safe.
|
|
26
|
+
const token = randomBytes(12).toString("hex"); // secret carried in user=<token>
|
|
25
27
|
const { privateKey } = generateKeyPairSync("rsa", {
|
|
26
28
|
// ponytail: rsa PEM parses cleanly in ssh2 (ed25519 PKCS8 is hit-or-miss)
|
|
27
29
|
modulusLength: 2048,
|
|
@@ -56,10 +58,13 @@ function bridge(stream, args, term) {
|
|
|
56
58
|
return child;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
const debug = process.env.CMUX_SSH_DEBUG ? (...a) => console.error("[debug]", ...a) : () => {};
|
|
62
|
+
|
|
59
63
|
const server = new Server({ hostKeys: [privateKey] }, (client) => {
|
|
60
|
-
client.on("authentication", (ctx) =>
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
client.on("authentication", (ctx) => {
|
|
65
|
+
debug("auth", ctx.method, ctx.username);
|
|
66
|
+
return ctx.username === token ? ctx.accept() : ctx.reject();
|
|
67
|
+
});
|
|
63
68
|
client.on("session", (accept) => {
|
|
64
69
|
const session = accept();
|
|
65
70
|
// Defaults; overwritten by pty/env requests before shell/exec.
|
|
@@ -67,12 +72,14 @@ const server = new Server({ hostKeys: [privateKey] }, (client) => {
|
|
|
67
72
|
let child;
|
|
68
73
|
|
|
69
74
|
session.on("pty", (a, _r, info) => {
|
|
75
|
+
debug("pty", info.term, info.cols, info.rows);
|
|
70
76
|
term.term = info.term || term.term;
|
|
71
77
|
term.cols = info.cols || term.cols;
|
|
72
78
|
term.rows = info.rows || term.rows;
|
|
73
79
|
a?.();
|
|
74
80
|
});
|
|
75
81
|
session.on("env", (a, _r, info) => {
|
|
82
|
+
debug("env", info.key, "=", info.val);
|
|
76
83
|
term.env[info.key] = info.val;
|
|
77
84
|
a?.();
|
|
78
85
|
});
|
|
@@ -81,6 +88,7 @@ const server = new Server({ hostKeys: [privateKey] }, (client) => {
|
|
|
81
88
|
a?.();
|
|
82
89
|
});
|
|
83
90
|
session.on("shell", (acc) => {
|
|
91
|
+
debug("shell");
|
|
84
92
|
// ponytail: route the interactive shell through tmux so sessions persist
|
|
85
93
|
// and are shared across LAN connections; show the session list on connect.
|
|
86
94
|
// Falls back to a plain login shell when tmux is absent.
|
|
@@ -92,7 +100,15 @@ const server = new Server({ hostKeys: [privateKey] }, (client) => {
|
|
|
92
100
|
child = bridge(acc(), ["-lc", start], term);
|
|
93
101
|
});
|
|
94
102
|
session.on("exec", (acc, _r, info) => {
|
|
95
|
-
|
|
103
|
+
debug("exec", info.command);
|
|
104
|
+
// ponytail: login shell (-lc) so PATH includes things like homebrew tmux;
|
|
105
|
+
// cmux runs remote commands (tmux probes, tmux -CC) over this channel.
|
|
106
|
+
child = bridge(acc(), ["-lc", info.command], term);
|
|
107
|
+
});
|
|
108
|
+
session.on("subsystem", (_acc, rej, info) => {
|
|
109
|
+
debug("subsystem", info.name);
|
|
110
|
+
// ponytail: scp/sftp not supported; reject so the client fails fast
|
|
111
|
+
rej?.();
|
|
96
112
|
});
|
|
97
113
|
});
|
|
98
114
|
});
|