Can I connect to ssh2 without the privateKey? - node.js

I can connect to ssh2 without the privateKey
I am trying to enter a server with SFTP but when I get the following error ...
Timed out while waiting for handshake
I'm looking for an example and almost everyone uses the privateKey, is it mandatory? and how is one generated?
My code is the following ...
var Client = require ('ssh2'). Client;
var conn = new Client ();
conn.on ('error', function (err) {
console.log ('SSH - Connection Error:' + err);
});
conn.on ('end', function () {
console.log ('SSH - Connection Closed');
});
conn.on ('ready', function () {
console.log ("------ enter ------");
// code to work with SSH
});
conn.connect ({
host: 'host',
username: 'user',
port: 22
password: 'password',
});

Related

How to make a SSH to postgres server with help of ssh2 library and query using pg libary?

I am trying to make a connection to Postgres remote host using the SSH tunnel from node application(library:ssh2) and query the data(lib:pg).
Before I used mysql2(node library) make a tunnel using ssh2(node library) and connected to Mysql remote host as well as able to query the data. But I want to do the same in Postgres remote host I am not able to connect to it.
pg Client obj config does not support the stream from ssh2 forwardOut..!
Or, Is there any library available to make this happen instead of that ssh2, pg
PS: In mysql2 when I try to make a connection with a mysql config with stream: stream key value.
var Clientssh = require('ssh2').Client;
var conn = new Clientssh();
conn.on('ready', function() {
console.log('Client :: ready');
conn.forwardOut(
'127.0.0.1',
5434,
'localhost',
5432,
function(err, stream) {
if (err) throw err;
let conf = {
host: 'localhost',
port: 5434,
user: 'test',
database: 'test',
password: 'test'
}
let remoteConnection = new Client(conf);
remoteConnection.connect(function(err) {
if (err) {
console.log(err);
console.log("Unable to connect to postgre");
res.send(err);
} else {
remoteConnection.query('SELECT * FROM test', function(err, testResult) {
remoteConnection.end();
if (err) {
console.log("Unable to fetch data");
res.send(err);
} else {
console.log("Succcess");
res.send(testResult);
}
});
}
});
});
}).connect({
host: 'hostaddress',
port: 'hostport',
username: 'hostusername',
privateKey: require('fs').readFileSync('path/for/key')
});
It shows the Connection terminated unexpectedly from this line
Client :: ready
Error: Connection terminated unexpectedly
at Connection.con.once (/node-postgres/node_modules/pg/lib/client.js:235:9)
at Object.onceWrapper (events.js:286:20)
at Connection.emit (events.js:198:13)
at Channel.<anonymous> (/node-postgres/node_modules/pg/lib/connection.js:131:10)
at Channel.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1129:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Unable to connect to postgre

Error: Can't add new command when connection is in closed state

I have recently deployed my node.js API application on live server. I am getting these issue on live server.
I have googled it, but could not get any exact solution. Can anyone suggest how can i solve this problem?
{ Error: read ETIMEDOUT at TCP.onread (net.js:622:25) errno: 'ETIMEDOUT', code: 'ETIMEDOUT', syscall: 'read', fatal: true }
{ Error: Can't add new command when connection is in closed state at PoolConnection._addCommandClosedState }
I amd using the mysql connection pool like this
var mysql = require('mysql2');
var mysqlPool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'xyz',
database: 'xyz',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = mysqlPool;
I had a similar problem and ended up having to put the connection request in it's own .js file and import it into the controller-
connectionRequest.js
module.exports = function () {
let mysql = require('mysql2')
let connCreds = require('./connectionsConfig.json');
//Establish Connection to the DB
let connection = mysql.createConnection({
host: connCreds["host"],
user: connCreds['username'],
password: connCreds['password'],
database: connCreds['database'],
port: 3306
});
//Instantiate the connection
connection.connect(function (err) {
if (err) {
console.log(`connectionRequest Failed ${err.stack}`)
} else {
console.log(`DB connectionRequest Successful ${connection.threadId}`)
}
});
//return connection object
return connection
}
Once I did that I was able to import it into my query on the controller file like so
ControllerFile.js
let connectionRequest = require('../config/connectionRequest')
controllerMethod: (req, res, next) => {
//Establish the connection on this request
connection = connectionRequest()
//Run the query
connection.query("SELECT * FROM table", function (err, result, fields) {
if (err) {
// If an error occurred, send a generic server failure
console.log(`not successful! ${err}`)
connection.destroy();
} else {
//If successful, inform as such
console.log(`Query was successful, ${result}`)
//send json file to end user if using an API
res.json(result)
//destroy the connection thread
connection.destroy();
}
});
},
After a lot of messing around I was able to solve the problem by destroying the connection, waiting (this is the important page) and getting the connection again.
conn = await connPool.getConnection();
// We have error: Can't add new command when connection is in closed state
// I'm attempting to solve it by grabbing a new connection
if (!conn || !conn.connection || conn.connection._closing) {
winston.info('Connection is in a closed state, getting a new connection');
await conn.destroy(); // Toast that guy right now
sleep.sleep(1); // Wait for the connection to be destroyed and try to get a new one, you must wait! otherwise u get the same connection
conn = await connPool.connection.getConnection(); // get a new one
}

Node-Redis: ready check failed - NOAUTH Authentication required

I have a strange redis behavior:
const redis = require('redis');
const { REDIS_URL: redisUrl, REDIS_PASSWORD: redisPassword } = process.env;
const client = redis.createClient(redisUrl, {
no_ready_check: true,
auth_pass: redisPassword
});
client.on('connect', () => {
redisPassword && client.auth(redisPassword);
});
client.on('error', err => {
global.console.log(err.message)
});
But all the time I receive following error:
throw er; // Unhandled 'error' event
ReplyError: Ready check failed: NOAUTH Authentication required.
Why unhandled ? I set onerror handler
Why Ready check failed ? I disabled it in options
I'm not sure why your code will throw this error. But I try this code in my local machine, it works well.
const redis = require('redis');
const redisPassword = "password" ;
const client = redis.createClient({
host : '127.0.0.1',
no_ready_check: true,
auth_pass: redisPassword,
});
client.on('connect', () => {
global.console.log("connected");
});
client.on('error', err => {
global.console.log(err.message)
});
client.set("foo", 'bar');
client.get("foo", function (err, reply) {
global.console.log(reply.toString())
})
And run node client.js will output :
connected
bar
NOAUTH Authentication required is caused by when redis process command , it found the client is not authenticated so it complained with it.
I guess maybe the redisUrl you give to createClient has some problem, try to debug it or change to my code's way to try. Hopefully you can fix it.
And one more thing: the client.auth(redisPassword) is not necessary because if you set an auth_pass or password option, the redis client will auto send auth command to server before any command.
If you have redis uri saved as string. You need decompose it to object. For ioredis you can use function
export function decomposeRedisUrl(url) {
const [[, , password, host, port]] = [...(url.matchAll(/redis:\/\/(([^#]*)#)?(.*?):(\d*)/g))];
return { password, host, port };
}
There are tests for this function:
it("redis url should be decomposed correctly with password", () => {
expect(decomposeRedisUrl("redis://pass#host.com:9183")).to.eql({
password: "pass",
host: "host.com",
port: "9183",
});
});
it("redis url should be decomposed correctly without password", () => {
expect(decomposeRedisUrl("redis://localhost:6379")).to.eql({
password: undefined,
host: "localhost",
port: "6379",
});
});
and usage
import Redis from "ioredis";
async function getKeysFromRedisUrl(url) {
const rc = new Redis(decomposeRedisUrl(url));
const keys = await rc.keys("*");
rc.disconnect();
return keys;
}
describe("Redis can connect", () => {
it("with cloud", async () => {
expect(await getKeysFromRedisUrl("redis://pass#host.com:9183")).to.be.an("array");
});
it("with local redis instance", async () => {
expect(await getKeysFromRedisUrl("redis://localhost:6379")).to.be.an("array");
});
});
user name is not handled in this function
if you're using docker to run Redis, check if your docker-compose has the command: redis-server --requirepass redis
Then check your .env file to make sure you're using it.
It was the problem here and I was able to fix it by adding the password at .env file.

Error: All configured authentication methods failed levels: 'client-authentication'

I am using node.js ssh2 module.I have installed ssh2 module by executing the command 'npm install ssh2'.However, when I use ssh2 to connect to a remote server, it always output the error:
[Error: All configured authentication methods failed] levels: 'client-authentication'
This is my code
var Client = require('ssh2').Client
var conn = new Client();
var option = {
host: '10.171.65.154',
port: 22,
username: 'root',
password: '123456'
};
conn.on('ready', function(){
console.log('Client :: ready');
conn.sftp(function(err, sftp){
if(err) throw err;
sftp.readdir('home', function(err, list){
if(err) throw err;
console.dir(list);
conn.end();
});
});
}).on('error', function(err){
console.log(err);
}).connect(option);
However, I can not connect successfully.I am sure the username and password are correct and I can connect successfully by SecureCRT.
it always output the error:
[Error: All configured authentication methods failed] levels: 'client-authentication'
Probably, you have to handle keyboard-interactive authentication (which is not the same as password). Try something like this:
connection.on('ready', function(){
console.log("Connected!");
}).on('error', function(err){
console.error(err);
}).on('keyboard-interactive', function (name, descr, lang, prompts, finish) {
// For illustration purposes only! It's not safe to do this!
// You can read it from process.stdin or whatever else...
var password = "your_password_here";
return finish([password]);
// And remember, server may trigger this event multiple times
// and for different purposes (not only auth)
}).connect({
host: "your.host.or.ip",
port: 22,
username: "your_login",
tryKeyboard: true
});

Node.js ORM mysql connect via SSH tunnel

I'm trying to set up a node.js application which uses node-orm2. However our cloud hosted DB can only be connected via SSH tunnel. Checking the ORM doc I can not see any config option to connect to the DB via SSH tunnel. Is there any way to set up this or I need to find some way to connect without SSH?
I updated the code example for tunnel-ssh 1.1.0, because it's actually the only working example on the internet (for so far i searched..).
It was quite a hassle to get this new tunnel-ssh configured...
var mysql = require('mysql');
var Tunnel = require('tunnel-ssh');
module.exports = function (server) {
return new Object({
tunnelPort: 33333, // can really be any free port used for tunneling
/**
* DB server configuration. Please note that due to the tunneling the server host
* is localhost and the server port is the tunneling port. It is because the tunneling
* creates a local port on localhost
*/
dbServer: server || {
host: '127.0.0.1',
port: 33333,
user: 'username',
password: 'yourpwd',
database: 'yourdb'
},
/**
* Default configuration for the SSH tunnel
*/
tunnelConfig: {
remoteHost: '127.0.0.1', // mysql server host
remotePort: 3306, // mysql server port
localPort: 33333, // a available local port
verbose: true, // dump information to stdout
disabled: false, //set this to true to disable tunnel (useful to keep architecture for local connections)
sshConfig: { //ssh2 configuration (https://github.com/mscdex/ssh2)
host: 'your_tunneling_host',
port: 22,
username: 'user_on_tunneling',
password: 'pwd'
//privateKey: require('fs').readFileSync('<pathToKeyFile>'),
//passphrase: 'verySecretString' // option see ssh2 config
}
},
/**
* Initialise the mysql connection via the tunnel. Once it is created call back the caller
*
* #param callback
*/
init: function (callback) {
/* tunnel-ssh < 1.0.0
//
// SSH tunnel creation
// tunnel-ssh < 1.0.0
var me = this;
me.tunnel = new Tunnel(this.tunnelConfig);
me.tunnel.connect(function (error) {
console.log('Tunnel connected', error);
//
// Connect to the db
//
me.connection = me.connect(callback);
});
*/
/* tunnel-ssh 1.1.0 */
//
// SSH tunnel creation
//
var me = this;
// Convert original Config to new style config:
var config = this.tunnelConfig;
var newStyleConfig = {
username: config.sshConfig.username,
port: config.sshConfig.port,
host: config.sshConfig.host,
// SSH2 Forwarding...
dstPort: config.remotePort,
dstHost: config.remoteHost,
srcPort: config.localPort,
srcHost: config.localHost,
// Local server or something...
localPort: config.localPort,
localHost: config.localHost,
privateKey: config.privateKey
}
me.tunnel = tunnel(newStyleConfig, function (err) {
console.log('Tunnel connected', err);
if (err) {
return callback(err);
}
me.connection = me.connect(callback);
});
},
/**
* Mysql connection error handling
*
* #param err
*/
errorHandler: function (err) {
var me = this;
//
// Check for lost connection and try to reconnect
//
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.log('MySQL connection lost. Reconnecting.');
me.connection = me.connect();
} else if (err.code === 'ECONNREFUSED') {
//
// If connection refused then keep trying to reconnect every 3 seconds
//
console.log('MySQL connection refused. Trying soon again. ' + err);
setTimeout(function () {
me.connection = me.connect();
}, 3000);
}
},
/**
* Connect to the mysql server with retry in every 3 seconds if connection fails by any reason
*
* #param callback
* #returns {*} created mysql connection
*/
connect: function (callback) {
var me = this;
//
// Create the mysql connection object
//
var connection = mysql.createConnection(me.dbServer);
connection.on('error', me.errorHandler);
//
// Try connecting
//
connection.connect(function (err) {
if (err) throw err;
console.log('Mysql connected as id ' + connection.threadId);
if (callback) callback();
});
return connection;
}
}
);
};
Finally it was resolved by dropping orm2 and using node-mysql and tunnel-ssh modules as in the code below.
var mysql = require('mysql');
var Tunnel = require('tunnel-ssh');
module.exports = function (server) {
return new Object({
tunnelPort: 33333, // can really be any free port used for tunneling
/**
* DB server configuration. Please note that due to the tunneling the server host
* is localhost and the server port is the tunneling port. It is because the tunneling
* creates a local port on localhost
*/
dbServer: server || {
host: '127.0.0.1',
port: 33333,
user: 'username',
password: 'yourpwd',
database: 'yourdb'
},
/**
* Default configuration for the SSH tunnel
*/
tunnelConfig: {
remoteHost: '127.0.0.1', // mysql server host
remotePort: 3306, // mysql server port
localPort: 33333, // a available local port
verbose: true, // dump information to stdout
disabled: false, //set this to true to disable tunnel (useful to keep architecture for local connections)
sshConfig: { //ssh2 configuration (https://github.com/mscdex/ssh2)
host: 'your_tunneling_host',
port: 22,
username: 'user_on_tunneling',
password: 'pwd'
//privateKey: require('fs').readFileSync('<pathToKeyFile>'),
//passphrase: 'verySecretString' // option see ssh2 config
}
},
/**
* Initialise the mysql connection via the tunnel. Once it is created call back the caller
*
* #param callback
*/
init: function (callback) {
//
// SSH tunnel creation
//
var me = this;
me.tunnel = new Tunnel(this.tunnelConfig);
me.tunnel.connect(function (error) {
console.log('Tunnel connected', error);
//
// Connect to the db
//
me.connection = me.connect(callback);
});
},
/**
* Mysql connection error handling
*
* #param err
*/
errorHandler: function (err) {
var me = this;
//
// Check for lost connection and try to reconnect
//
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.log('MySQL connection lost. Reconnecting.');
me.connection = me.connect();
} else if (err.code === 'ECONNREFUSED') {
//
// If connection refused then keep trying to reconnect every 3 seconds
//
console.log('MySQL connection refused. Trying soon again. ' + err);
setTimeout(function () {
me.connection = me.connect();
}, 3000);
}
},
/**
* Connect to the mysql server with retry in every 3 seconds if connection fails by any reason
*
* #param callback
* #returns {*} created mysql connection
*/
connect: function (callback) {
var me = this;
//
// Create the mysql connection object
//
var connection = mysql.createConnection(me.dbServer);
connection.on('error', me.errorHandler);
//
// Try connecting
//
connection.connect(function (err) {
if (err) throw err;
console.log('Mysql connected as id ' + connection.threadId);
if (callback) callback();
});
return connection;
}
}
);
};
You can use the settings parameters to node-orm2 in order pass an options object to the underlying driver. For example, if you are using a mysql then you can pass an ssl option. See https://github.com/felixge/node-mysql#ssl-options in this case.
Thanks for the existing answers in this thread. The following solution worked for me:
function connect() {
return new Promise(async resolve => {
let tunnelPort = 33000 + Math.floor(Math.random() * 1000);
Tunnel({
//First connect to this server over ssh
host: '6.6.6.6',
username: 'vagrant',
privateKey: await fs.readFile('path/to/private_key'),
//And forward the inner dstPort (on which mysql is running) to the host (where your app is running) with a random port
dstPort: 3306,
localPort: tunnelPort
}, (err) => {
if (err) throw err;
console.log('Tunnel connected');
let connection = mysql.createConnection({
//Now that the tunnel is running, it is forwarding our above "dstPort" to localhost/tunnelPort and we connect to our mysql instance.
host: '127.0.0.1',
port: tunnelPort,
user: 'root',
password: 'password',
database: 'dbName'
});
connection.on('error', err => { throw err; });
connection.connect((err) => {
if (err) throw err;
console.log('Mysql connected as id ' + connection.threadId);
resolve(connection);
});
});
})
}

Resources