ssh2 icon indicating copy to clipboard operation
ssh2 copied to clipboard

How to set server side Pseudo-TTY settings > modes (terminal modes), e.g. ONLCR

Open yogch opened this issue 1 year ago • 1 comments

I'm trying to create a node js server using ssh2. I've took one of the server examples and modified it.

After a successful connection through regular Ubuntu ssh client towards my node js server, and a shell event, I create a stream.

}).on('shell', (accept, reject) => {
...
const stream = accept();

Then, I call an internal command that returns a buffer. When I use console.log('stdout: ' + data);, the output it printed fine, on the server side log. For example:

This is a test

But when returning this buffer to the client using stream.write(data);, the ssh client side prints something like:

This      is         
       a         test

Looks like something is wrong with \r or \n. I can't say for sure. I wanted to try and solve it using terminal modes. For example ONLCR which is written here , but couldn't find any example for usage of changing terminal modes.

Please help, Thanks

yogch avatar Jul 24 '24 21:07 yogch

The terminal modes are sent by the client and it's up to the server to honor them. Same with the rest of the pty info (e.g. rows, columns, terminal type, etc.).

It would be helpful if you could show exactly how the client is rendering what the server is sending back. For a string like "This is a test" there should be no additional spaces being added between the words like you've shown. Perhaps you should inspect the actual bytes of data to see if it contains terminal escape sequences or other special control characters such as CR and/or LF.

mscdex avatar Jul 24 '24 22:07 mscdex

Indeed I tried to simplify my issue, but due to that I didn't add some data. Right, my string has \n in it. Thanks to your suggestion, I printed the hex of data and saw all the lines end with \n. I'm using ssh from Linux so it would seem right (not to have \r). But the ssh client prints are wrong. So, a better example is:

This\n
is\n
a\n
test\n

(emphasizing the \n) And I get it as

This                is              a                test

I wrote some data manually with \r in the end:

stream.write(new Buffer([0x2a, 0x2a, 0x0a, 0x0d]));

The ssh client showed the output correctly.

Now, I can either add \r to all of my stream.write()s (append \r whenever I see \n). Or understand if this is an appropriate behavior of the server/client? Is there something I could do?

It would be helpful if you could show exactly how the client is rendering what the server is sending back

What do you mean by that? I'm using a regular ssh on Ubuntu. BTW, when the client requests pty, the info's modes is empty. term is term: 'xterm-256color'

Thank you very much!

yogch avatar Jul 25 '24 10:07 yogch

The problem is that OpenSSH is expecting a real pty to be allocated and used for the shell session. The pty would be doing the LF->CRLF conversions (and observing any terminal modes requested). Since you are not using a real pty, you need to instruct OpenSSH to not request one, which will cause OpenSSH to interpret the output as you're expecting. You can do this by passing -T to OpenSSH.

If you are executing a command on the server side that really does need a pty (and if the client is requesting one of course), then you can use a module like node-pty to allocate one and hook it up to the shell stream you got back from accept().

mscdex avatar Jul 25 '24 13:07 mscdex

Thank you very much!

If I may, last question: so, in case the client asks for pty in the event on session,should I just take the request, and use the cols, rows if the info when I spawn my pty process in the shell event ? Is that the desired flow?

yogch avatar Jul 25 '24 18:07 yogch

You'd pass all of the information, including the terminal type. I'm not sure if node-pty (not to be confused with pty on npm) supports an explicit list of terminal modes though.

mscdex avatar Jul 25 '24 19:07 mscdex