Adding samba user programically with node.js - node.js

I've wrote function in node,js as follows:
const addUserToSamba = (userLogin, password) => {
const echoPassword = spawnSync('echo', ['ne',`${password}\n${password}\n`]);
const addUserCredentialsToSamba = spawnSync('smbpasswd', ['-a', '-s', userLogin], {
input: echoPassword.stdout,
});
console.log('Added user credentials to Samba configuration');
console.log(addUserCredentialsToSamba.stderr.toString());
console.log(addUserCredentialsToSamba.stdout.toString());
}
I want to achieve something like this in bash:
echo -ne "$PASS\n$PASS\n" | smbpasswd -a -s $LOGIN
When I'm running addUserToSamba(userLogin, password); function with given userlLogin and user password then I even get message Added user ${userLogin} as a stdout of the addUserCredentialsToSamba outcome.
But the credentials don't work.
Have I correctly rewritten this bash function to the node.js one?
If no, how can I fix it?

You can simply skip the echo part and output the credentials directly to the smbpasswd process:
const addUserCredentialsToSamba = spawnSync('smbpasswd', ['-a', '-s', userLogin], {
input: `${password}\n${password}\n`,
});

Related

Get password for node-cli and pass it on to next command in nodejs

Im trying to build a command line interface using nodejs. I have used enquirer package to prompt users for questions. I have a scenario where i need to write to /etc/hosts file. I tried running the following command using execa package
const {stdout} = await execa.command('echo "192.241.xx.xx venus.example.com venus" >> /etc/hosts', { cwd: '/etc/'})
But it does not seems to work and tried with sudo command as well
const {stdout} = await execa.command("sudo vim hosts", { cwd: '/etc/'});
How to execute it in nodejs. Basically i wanted to prompt the user for password and then need to write it to /etc/hosts file.
FYKI: im using execa for executing shell commands.
Tried the hostile.js and it didn't work either.
Here is the full code
async function executeCommand() {
try {
const {stdout} = await execa.command("echo '192.34.0.03 subdomain.domain.com' | sudo tee -a /etc/hosts", { cwd: '/etc/'});
console.log(stdout);
} catch (error) {
console.log(error);
process.exit(1);
}
}
There is a Node package for this purpose, called password-prompt:
let prompt = require('password-prompt');
let password = prompt('password: ');
And now that you have the password, you can run something like this:
let command = `echo "${password}" | sudo -S -k vim /etc/hosts`;
This solution worked for me
const { promisify } = require('util');
const exec = promisify(require('child_process').exec)
const nameOutput = await exec("echo '127.0.0.1 test.com' | sudo tee -a /etc/hosts")
This would prompt password to enter.

How to allow Node.js child_process.execSync to run `scp -P 4422 root#myserver.com:/data/backups/...` without getting Permission Denied

I am running a simply Node.js process to backup my data everyday by using child_process.execSync to run:
scp -P 4422 root#myserver.com:/data/backups/dbs.zip /data/backups/dbs.zip
Notice if I run the above command directly, it will work. But when I do it in Node, the log I got is:
[2020-03-04 05:00:00] error downloading backup...Command failed:
Permission denied, please try again.
root#myserver.com: Permission denied (publickey,password).
Do I have to create a key file for Node.js' child_process to use when it fires scp? If so, how come if I run scp -i id_rsa.pem -P 4422 root#myserver.com:/data/backups/dbs.zip /data/backups/dbs.zip in Node.js it just stuck (like it even stops running any async actions such as appendFile. It also created a lot of processes called (node) and these processes cannot be killed.
const path = require('path');
const {
backupPath,
downloadPath
} = require('../../conf');
const keyPath = path.join(
__dirname,
'../../key/id_rsa.pem'
);
const downloadProcess = log => {
const { execSync } = require('child_process');
log('downloading backup...');
try {
const date = new Date();
const backupName = `db_${date.format('yyyy-MM-dd')}.tar.gz`;
const command = `scp -i ${keyPath} -P 4422 root#myserver.com:${backupPath}/${backupName} ${downloadPath}/${backupName}`;
log(`running command: ${command}`);
const stdout = execSync(command);
log(`downloaded backup ${backupName} at ${downloadPath}${'\n'}stdout:${'\n'}${stdout}`);
} catch (e) {
log(`error downloading backup...${e.message}`);
}
}
module.exports = downloadProcess;

Spawn command with redirection

Let say I have this command
somecli -s < "/path/to/file.txt"
How can I convert the above command to NodeJS spawn command ? I did something like this, but seems like it didn't pass the input.
spawn('somecli', ['-s', '<', '"/path/to/file.txt"'], { stdio: 'inherit'}).on('error', function (error) {
// something
});
I can use the exec command below and it's working, but I prefer if we can see the live output.
exec('somecli -s < "/path/to/file.txt"', (e, stdout, stderr) => {
// something
})
something like this should help
const { spawn } = require('child_process');
const fs = require('fs');
const writeStream = fs.createWriteStream("/path/to/file.txt");
const shell = spawn('somecli', ['-s']);
shell.stdout.pipe(writeStream);
To pass file input to command ( STDIN redirection )
$ somecli -s < /path/to/file.txt
We can do it something like this
spawn('somecli', ['-s'], {stdio: [fs.openSync('/path/to/file.txt', 'r'), process.stdout, process.stderr]});
To pass command output to file ( STDOUT redirection )
$ somecli -s > /path/to/file.txt
You may follow Ashish answer
let s = spawn('somecli', ['-s])
s.stdout.pipe(fs.createWriteStream('/path/to/file.txt'))

How to start an interactive terminal window on mac using child_process library of node?

I want to execute a bash command - dotnet dev-certs https --trust in an interactive terminal through child_process library.
Since it asks for the user password, it has to be interactive terminal.
I've already tried using AppleScript for it, but the user experience is subpar since it tends to leave half-closed terminal windows around.
Edit - Added the code snippet that I am using to create a child_process.
import * as cp from 'child_process'
cp.spawn('dotnet dev-certs https --trust', {})
I've tried many many combinations of cp.spawn and cp.exec.
e.g. cp.spawn('...', { shell: true, stdio: 'ignore', detached: true }) etc.
cp.spawn actually creates a process, but it's not interactive and immediately terminates.
You have to filter the incoming data from stdout with stdout.on('data', data => {}) to find the shell request for user input. After you found that specific line you can simply send data to the shell via the stdin.write('any input \n')
import * as cp from 'child_process'
const ls = cp.spawn('dotnet dev-certs https --trust', {})
ls.stdout.on('data', function (data) {
const currentData = data.toString();
//check for password input notification:
if(currentData === "input credentials: ")
{
//send the password via stdin. \n does the trick over here.
ls.stdin.write('Password\n');
}
});

Commander.js - Implementing sub commands that executes when the previous one is finished

I'm using Commander.js to write my own CLI. I managed to write commands that work individually but now I need to implement sub commands but the docs are a bit vague and confusing so I haven't been able to figure out.
What I want is the connect command to connect to a MongoDB instance and when it has done that proceed to execute the get command. How can I achieve this?
These are the commands and package.json:
./package.json:
{
...
"main": "./commands/my-cli.js",
"bin": "./commands/my-cli.js",
...
}
./commands/my-cli.js:
const commander = require('commander');
const program = new commander.Command();
const connect = require('./my-cli-connect');
const get = require('./my-cli-get');
// Initialize each command
connect(program);
get(program);
./commands/my-cli-connect.js:
function connect(program) {
program
.command('connect <db> <username> <password>', 'Connects to a database')
.action((db, username, password) => {
MongoClient.connect(<some-mongo-url>, {useNewUrlParser: true}, (err, connection) => {
assert.equal(null, err, 'Failed to connect to MongoDB instance');
// Continue here with the get command
});
});
program.parse(process.argv);
}
module.exports = connect;
./commands/my-cli-get.js:
function get(program) {
program
.command('get <collection>')
.option('-q,--query <query>', 'Search terms', jsonParser, {})
.description('Returns documents from a MongoDB collection')
.action(action);
program.parse(process.argv);
function action(collection, options) {
// This never runs
console.log('hello world');
}
}
module.exports = get;
Running my-cli --help shows these available commands:
...
Commands:
connect <db> <username> <password> Connects to a database
help [cmd] display help for [cmd]
Example command execution that should call both connect and then get when connect has finished connecting:
$ my-cli connect myDb myUser myPass get users -q '{"email": "foo#gmail.com"}'
Right now the get command's action function never runs.

Resources