Skip to content

Commit 5462574

Browse files
committed
fix: properly handle SSH PTY dimensions on initial connection (#350)
- Store terminal dimensions (cols/rows) in sessionState during authentication - Separate PTY options from environment options in SSH shell() method - Fix SSH2 library parameter interpretation issue that prevented initial dimensions from being applied This ensures the SSH2 library correctly sets PTY dimensions when creating the shell, resolving the issue where terminals would show 24x80 instead of actual dimensions.
1 parent 252d480 commit 5462574

File tree

4 files changed

+48
-21
lines changed

4 files changed

+48
-21
lines changed

app/socket.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,23 @@ class WebSSH2Socket extends EventEmitter {
106106

107107
handleAuthenticate(creds) {
108108
debug(`handleAuthenticate: ${this.socket.id}, %O`, maskSensitiveData(creds))
109+
debug(`handleAuthenticate: received cols=${creds.cols}, rows=${creds.rows}`)
109110

110111
if (isValidCredentials(creds)) {
111112
// Set term if provided, otherwise use config default
112113
this.sessionState.term = validateSshTerm(creds.term) ? creds.term : this.config.ssh.term
113114

115+
// Store terminal dimensions if provided with credentials
116+
if (creds.cols && validator.isInt(creds.cols.toString())) {
117+
this.sessionState.cols = parseInt(creds.cols, 10)
118+
debug(`handleAuthenticate: storing cols: ${this.sessionState.cols}`)
119+
}
120+
if (creds.rows && validator.isInt(creds.rows.toString())) {
121+
this.sessionState.rows = parseInt(creds.rows, 10)
122+
debug(`handleAuthenticate: storing rows: ${this.sessionState.rows}`)
123+
}
124+
debug(`handleAuthenticate: sessionState now has cols=${this.sessionState.cols}, rows=${this.sessionState.rows}`)
125+
114126
this.initializeConnection(creds)
115127
} else {
116128
debug(`handleAuthenticate: ${this.socket.id}, CREDENTIALS INVALID`)
@@ -212,15 +224,16 @@ class WebSSH2Socket extends EventEmitter {
212224
// Get envVars from socket session if they exist
213225
const envVars = this.socket.request.session.envVars || null
214226

227+
const shellOptions = {
228+
term: this.sessionState.term || 'xterm-color',
229+
cols: this.sessionState.cols || 80,
230+
rows: this.sessionState.rows || 24,
231+
}
232+
233+
debug(`createShell: Creating shell with options:`, shellOptions)
234+
215235
this.ssh
216-
.shell(
217-
{
218-
term: this.sessionState.term,
219-
cols: this.sessionState.cols,
220-
rows: this.sessionState.rows,
221-
},
222-
envVars
223-
)
236+
.shell(shellOptions, envVars)
224237
.then((stream) => {
225238
stream.on('data', (data) => {
226239
this.socket.emit('data', data.toString('utf-8'))

app/ssh.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,26 @@ class SSHConnection extends EventEmitter {
276276
* @returns {Promise<Object>} - A promise that resolves with the SSH shell stream
277277
*/
278278
shell(options, envVars) {
279-
const shellOptions = Object.assign({}, options, {
280-
env: this.getEnvironment(envVars),
281-
})
279+
// Separate PTY options from environment options
280+
// SSH2 expects them as separate parameters
281+
const ptyOptions = {
282+
term: options.term,
283+
rows: options.rows,
284+
cols: options.cols,
285+
width: options.width,
286+
height: options.height,
287+
}
288+
289+
// Only include environment options if we have envVars
290+
const envOptions = envVars ? {
291+
env: this.getEnvironment(envVars)
292+
} : undefined
293+
294+
debug(`shell: Creating shell with PTY options:`, ptyOptions, 'and env options:', envOptions)
282295

283296
return new Promise((resolve, reject) => {
284-
this.conn.shell(shellOptions, (err, stream) => {
297+
// Pass PTY options as first param, env options as second
298+
this.conn.shell(ptyOptions, envOptions, (err, stream) => {
285299
if (err) {
286300
reject(err)
287301
} else {

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"jsmasker": "^1.4.0",
4141
"read-config-ng": "~3.0.7",
4242
"socket.io": "^4.8.1",
43-
"ssh2": "1.16",
43+
"ssh2": "1.17",
4444
"validator": "^13.15.15",
4545
"webssh2_client": "^0.2.29"
4646
},

0 commit comments

Comments
 (0)