簡體   English   中英

如何創建交互式 ssh 終端並在 Meteor 應用程序中使用 Node JS 從瀏覽器輸入命令

[英]how to create interactive ssh terminal and enter commands from the browser using Node JS in a Meteor app

我正在嘗試創建一個 web 頁面,用戶可以在其中使用用戶名/密碼通過 ssh 對遠程服務器進行身份驗證,然后與遠程服務器交互。

我不希望創建一個完整的交互式終端:應用服務器將根據用戶輸入執行一組有限的命令,然后將響應傳遞回瀏覽器。

不同的用戶應該與不同的 ssh 會話進行交互。

我的應用程序是在 Meteor 1.8.1 中構建的,因此后端在 Node JS 版本 9.16.0 下運行。 它使用 Phusion Passenger 部署到 Ubuntu。

我查看了幾個可以創建交互式 ssh session 的軟件包,但我缺少有關如何使用它們的基本知識。

例如https://github.com/mscdex/ssh2#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”,然后關閉 session。 在我正在尋找的意義上,它不是“交互式”的。 我看不到的是如何讓 session 保持活動狀態並發送新命令?

這個完整終端的示例對於我的需求來說似乎有點過頭了,我不會使用 Docker。

此示例使用 socket.io,我不確定這將如何與我的 Meteor 應用程序交互? 我目前正在使用 Meteor 方法和出版物在客戶端和服務器之間傳遞信息,所以我希望需要使用 Meteor 基礎設施的“流星型”解決方案?

child_process.spawn 有效,但只會發送一個命令,它不維護 session。

我知道其他人也問過類似的問題,但我沒有看到針對我的特定案例的解決方案。 感謝您的任何幫助。

我按照這些在瀏覽器中創建交互式終端的說明以及使用 socket.io 和 Meteor 的說明來完成這項工作

由於包的變化,這兩組指令都需要一些更新:

我使用了這些軟件包:

SSH2

xterm

xterm-addon-fit

socket.io

socket.io 客戶端

並且還必須卸載 meteor-mode-stubs 並重新安裝它以獲得不依賴 Buffer polyfill 的最新版本。

這是我的代碼。

前端:

我的終端.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');
        });
    });
});

服務器:

服務器/main.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 運行時的文件中加載。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM