如何在Meteor应用中使用Node JS创建交互式ssh终端并从浏览器中输入命令。

问题描述 投票:0回答:1

我试图创建一个网页,用户可以通过ssh用usernamepassword认证到远程服务器,然后与远程服务器交互。

我不希望创建一个完整的交互式终端:应用服务器将根据用户输入执行一组有限的命令,然后将响应传回浏览器。

不同的用户应该用不同的ssh会话进行交互。

我的应用是用Meteor 1.8.1构建的,所以后端运行在Node JS下,版本为9.16.0。它是用Phusion Passenger部署到Ubuntu上的。

我看了几个可以创建交互式ssh会话的包,但我缺少一些关于如何使用它们的基本知识。

比如说 https:/github.commscdexssh2#start-an-interactive-shell-session。

这个例子显示了这样的代码。

var Client = require('ssh2').Client;

var conn = new Client();
conn.on('ready', function() {
  console.log('Client :: ready');
  conn.shell(function(err, stream) {
    if (err) throw err;
    stream.on('close', function() {
      console.log('Stream :: close');
      conn.end();
    }).on('data', function(data) {
      console.log('OUTPUT: ' + data);
    });
    stream.end('ls -l\nexit\n');
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  privateKey: require('fs').readFileSync('/here/is/my/key')
});

这个例子连接到远程服务器,执行一个命令 "ls" 然后关闭会话。这不是我想要的 "交互式"。我不明白的是,如何保持会话的活力并发送新的命令?

这个例子 的一个完整的终端,对于我的需求来说,似乎是矫枉过正,而且我也不会使用Docker。

这个例子 使用socket.io,我不知道这将如何与我的Meteor应用交互?我目前使用Meteor方法和出版物在客户端和服务器之间传递信息,所以我希望需要一个使用Meteor基础架构的 "Meteor型 "解决方案?

child_process.spawn可以工作,但只会发送一条命令,它不会维护一个会话。

我知道其他人也问过类似的问题,但我没有看到针对我的特殊情况的解决方案。谢谢你的帮助。

node.js meteor ssh
1个回答
0
投票

我通过以下方法实现了这个工作 这些说明用于在浏览器中创建交互式终端。以下是使用Meteor的socket.io的说明。.

由于包的变化,这两套指令都需要更新。

  • meteor-node-stubs现在使用stream-http而不是http-browserify。https:/github.commeteornode-stubsissues14。 所以,不要用黑客的方法来套接字

  • xterm附加组件(fit)现在是独立的包。

  • xterm API改变了,用term.onData(...)代替term.on('data'...)

我使用了这些包。

ssh2

xterm

xterm-addon-fit

socket.io

socket.io-client

并且还不得不卸载流星模式-stubs,然后重新安装,得到一个不依赖Buffer polyfill的最新版本。

这是我的代码。

前端。

myterminal.html

<template name="myterminal">
    <div id="terminal-container"></div>
</template>

我的终端.js

import { Template } from 'meteor/templating';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';

import './xterm.css'; // copy of node_modules/xterm/css/xterm.css
// xterm css is not imported:
// https://github.com/xtermjs/xterm.js/issues/1418
// This is a problem in Meteor because Webpack won't import files from node_modules: https://github.com/meteor/meteor-feature-requests/issues/278

const io = require('socket.io-client');

Template.fileExplorer.onRendered(function () {
    // Socket io client
    const PORT = 8080;

    const terminalContainer = document.getElementById('terminal-container');
    const term = new Terminal({ 'cursorBlink': true });
    const fitAddon = new FitAddon();
    term.loadAddon(fitAddon);
    term.open(terminalContainer);
    fitAddon.fit();

    const socket = io(`http://localhost:${PORT}`);
    socket.on('connect', () => {
        console.log('socket connected');
        term.write('\r\n*** Connected to backend***\r\n');

        // Browser -> Backend
        term.onData((data) => {
            socket.emit('data', data);
        });

        // Backend -> Browser
        socket.on('data', (data) => {
            term.write(data);
        });

        socket.on('disconnect', () => {
            term.write('\r\n*** Disconnected from backend***\r\n');
        });
    });
});

服务器。

servermain.js

const server = require('http').createServer();

// https://github.com/mscdex/ssh2
const io = require('socket.io')(server);
const SSHClient = require('ssh2').Client;

Meteor.startup(() => {
    io.on('connection', (socket) => {
        const conn = new SSHClient();
        conn.on('ready', () => {
            console.log('*** ready');
            socket.emit('data', '\r\n*** SSH CONNECTION ESTABLISHED ***\r\n');
            conn.shell((err, stream) => {
                if (err) {
                    return socket.emit('data', `\r\n*** SSH SHELL ERROR: ' ${err.message} ***\r\n`);
                }
                socket.on('data', (data) => {
                    stream.write(data);
                });
                stream.on('data', (d) => {
                    socket.emit('data', d.toString('binary'));
                }).on('close', () => {
                    conn.end();
                });
            });
        }).on('close', () => {
            socket.emit('data', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
        }).on('error', (err) => {
            socket.emit('data', `\r\n*** SSH CONNECTION ERROR: ${err.message} ***\r\n`);
        }).connect({
            'host': process.env.URL,
            'username': process.env.USERNAME,
            'agent': process.env.SSH_AUTH_SOCK, // for server which uses private / public key
            // in my setup, already has working value /run/user/1000/keyring/ssh
        });
    });

    server.listen(8080);
});

请注意,我是从一台有ssh权限的机器通过公钥连接到远程服务器的。根据你的设置,你可能需要不同的凭证。环境变量是在Meteor运行时从一个文件中加载的。

© www.soinside.com 2019 - 2024. All rights reserved.