Я использую ssh2 и socket.io , чтобы включить соединение s sh в реальном времени с удаленным сервером для пользователей моего Meteor 1.8 .1 приложение. Приложение работает на Ubuntu под Nginx и Phusion Passenger. Вот что необходимо приложению:
- Каждый авторизованный пользователь уже имеет учетную запись на удаленном сервере.
- Пользователь начнет сеанс, введя свои учетные данные и щелкнув значок " кнопка подключения "в приложении.
- Пользователь может просматривать списки каталогов в своем домашнем каталоге на удаленном сервере.
- Ни один пользователь не должен иметь доступа к сеансу sh другого пользователя.
- Их сеанс s sh должен быть удален с сервера, когда пользователь нажимает кнопку «отключить».
У меня работает s sh соединение, но я не могу понять узнал, как разрушить соединение s sh в конце сеанса пользователя. Каждый раз, когда они нажимают «разъединить», затем «подключиться», запускается другой сеанс s sh, а старый сеанс s sh все еще работает, поэтому каждая отправленная команда s sh выполняется несколько раз и отправляется несколько ответов. в браузер.
Меня также беспокоит, что соединение небезопасно; в процессе разработки я создаю сервер с помощью require ('http'). createServer () ;. В производстве на моем Ubuntu сервер с настроенным SSL, достаточно ли использовать require ('https'). createServer (); или требуется другая конфигурация, например, Nginx? Socket.io возвращается к старым технологиям, когда веб-сокет недоступен; как это защищено?
Главный вопрос: почему я вижу дублирующиеся сеансы S SH каждый раз, когда пользователь отключается, а затем подключается?
Второй вопрос: где я могу найти актуальные инструкции по защите socket.io? Или мне следует отказаться от socket.io и использовать WebSocket?
Я читал много статья es и сообщения о переполнении стека, но я нахожу это очень запутанным, и большая часть материала устарела. Например, socketio-auth не поддерживается. Я почти ничего не могу найти в документации Socket.io по аутентификации или авторизации - есть запись рукопожатие , но мне не ясно, нужна ли мне эта функция или как используйте его.
Вот мой код.
Сервер
io.on('connection', (socket) => {
console.log('socket id', socket.id); // this shows a new id after disconnect / reconnect
const conn = new SSHClient();
socket.on('disconnect', () => {
console.log('disconnect on server');
conn.end();
});
conn.on('ready', () => {
socket.emit('message', '*** SSH CONNECTION ESTABLISHED ***');
socket.emit('ready', 'ready');
conn.shell((err, stream) => {
stream.write('stty -echo \n'); // don't echo our own command back, or the user's password...
if (err) {
return socket.emit('message', `*** SSH SHELL ERROR: ' ${err.message} ***`);
}
socket.on('path', (path) => {
// path is a request for a directory listing
if (typeof path === 'string') {
const bashCommand = `ls -l ${path} --time-style=full-iso`;
console.log('*** WRITE'); // if you disconnect and reconnect this runs twice. Disconnect and reconnect again, it runs 3 times.
console.log('socket id again', socket.id); // this shows the same new socket id each time
stream.write(`${bashCommand} \n`);
}
});
stream.on('data', (d) => {
socket.emit('data', response); // tell the browser!
}).on('close', () => {
conn.end();
});
});
}).on('close', () => {
socket.emit('message', '*** SSH CONNECTION CLOSED ***');
}).on('error', (err) => {
socket.emit('message', `*** SSH CONNECTION ERROR: ${err.message} ***`);
}).connect({
'host': hosturl,
'username': ausername,
'agent': anagent, // just for dev I'm using public / private key from my local machine but this will be replaced with the user's entered credentials
});
}).on('disconnect', () => {
console.log('user disconnected');
});
server.listen(8080);
Клиент:
const io = require('socket.io-client');
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
const PORT = 8080;
let socket;
myEmitter.on('connectClicked', () => {
if (socket) {
this.connected.set(socket.connected);
}
if (this.connected.get() === false) {
socket = io(`http://localhost:${PORT}`);
socket.on('connect', () => {
this.connected.set(true);
socket.on('ready', () => {
console.log('ready');
});
// Backend -> Browser
socket.on('message', (data) => {
console.log('socket on message', data);
});
// Backend -> Browser
socket.on('data', (data) => {
console.log('got data', data);
this.parseResponse(data); // client function to handle data, not shown here
});
// Browser -> Backend
myEmitter.on('selectDirectory', () => {
console.log('*** SELECT DIRECTORY');
socket.emit('path', pathArray.join('/')); // path array is set in client code, it is a simple array of directory names
});
socket.on('disconnect', () => {
console.log('\r\n*** Disconnected from backend***\r\n');
this.connected.set(false);
});
});
}
myEmitter.on('disconnectClicked', () => {
socket.disconnect();
});
});