Node.JS Child_Process Catching Password Prompt - javascript

How do I use node.js child_process to programatically allow me to supply a password.
const spawn = require('child_process').spawn;
const ls = spawn('sudo ls');
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
The above throws an error. I am trying to figure out where exactly I can catch where it is wanting the password input and supply that via an environment variable.
I am hoping I can catch when it says Password check to make sure its saying that and then pass the password.

The error is because you're using the spawn command incorrectly.. It should be:
const ls = spawn('sudo', ['ls']);
Arguments to the child process are specified as the second argument (in an array).
You should then see the prompt for password, and I imagine be able to write to stdin to enter the password (which you're wanting to pass from process.env based on what you've said).
Edit: Quick search on SO seems to suggest it may not be as straight forward as writing to stdin after the prompt..

Related

Execute PowerShell script in Node.js

I create register app with node.js and Express.js
So it has name form and password form and submit button.
I want to make it, When I clicked the submit button, run the powershell script. This script means, add local windows user and set the password.
In PowerShell this script works well. And this powershell script should be run as administrator.
$PASSWORD= ConvertTo-SecureString –AsPlainText -Force -String kamisama123##
New-LocalUser -Name "gohan" -Description "sleepy" -Password $PASSWORD
After this command the local user is created.
I use node-powershell package in my code. This code means When I submit the my information and run the PowerShell script and add information in to mongodb
router.post(`/submit`, async function (req, res) {
let name = req.body.name;
let password = req.body.password;
let passwordCheck = req.body.passwordCheck;
let company = req.body.company;
let registerStatus = false;
let executives = req.body.executives;
let registerDate = Date.now();
let ps = new Shell();
let cmd = new PSCommand(`$PASSWORD= ConvertTo-SecureString ?AsPlainText -Force -String ${password}`)
let script = new PSCommand(`New-LocalUser -Name "${name}" -FullName "${name}" -Description "${name}" -PasswordNeverExpires -Password $PASSWORD`)
ps.addCommand(cmd);
ps.addCommand(script);
ㅡㅛ
try {
if (password !== passwordCheck) {
res.redirect('/')
} else {
let encodedPassword = Base64.encode(password);
await User.create({
name,
password: encodedPassword,
company,
registerStatus,
executives,
registerDate
}, (err, result) => {
if (err) throw err;
})
res.redirect(`/success/${name}`)
}
} catch (err) {
throw err;
}
})
But the error throws
(node:21596) UnhandledPromiseRejectionWarning: TypeError: Shell is not a constructor
I don't know where the error comes from.
Constructor is a term from object-oriented programming (OOP), every object in OOP has a constructor function.
For the shell object the constructor can not be empty (shell() has empty brackets)
Normally the constructor of shell has two arguments: execution policy and noProfile
let ps = new shell({
executionPolicy: 'Bypass',
noProfile: true
});
https://rannn505.gitbook.io/node-powershell/start
https://www.jeansnyman.com/posts/executing-powershell-commands-in-a-nodejs-api/
In How to execute Powershell script function with arguments using Node JS? is possibly a solution for this issue. The powershell script has to be wrapped in a promise in nodejs (and possibly be dot-sourced) :
How to execute Powershell script function with arguments using Node JS?
Powershell and potentially also node.js implements the OOP (object-oriented programming) design paradigms and semantics i.e. when writing object-oriented code each class has to have a constructor (new()) and a destructor (remove...) and it should have get() and set() methods to access (read and write) the fields (or attributes) of a class. In ps this is straighlty implemented
It is also possible to use object-oriented design patterns in PS https://dfinke.github.io/powershell,%20design%20patterns/2018/04/13/PowerShell-And-Design-Patterns.html

Writing code inside sudo.exec in Electron App

I need to execute code with admin rights at many places. I find sudo.exe and successfully prompt user for permission and password. I still could not figure out how exactly to use sudo.exe. As I am getting same error of permission denied while deleting a file that need admin permission. That is how my code looks like:
const fs = require('fs')
var sudo = require('sudo-prompt');
var options = {
name: 'Electron',
};
sudo.exec('echo hello', options,
function(error, stdout, stderr) {
if (error) throw error;
// Code that I want to run with admin rights
fs.unlinkSync("/private/var/log/fsck_hfs.log", (err) => {
alert("File succesfully deleted");
});
}
);
I think this method can only be used to run command, like echo hello in this case. What if I actually want to execute a chunk of code instead of a command?
Does this method works or these is any other approach available?
Is there a better method available in Electron to get privileges?
You can see the admin prompt approach in a popular Electron app: https://github.com/microsoft/vscode
In the package.json file they have two useful dependencies:
https://www.npmjs.com/package/native-is-elevated
https://www.npmjs.com/package/#vscode/sudo-prompt
They check to see if permissions are elevated using native-is-elevated, and if not, prompt for an admin password using sudo-prompt.
You can read the source code for the process here: https://github.com/microsoft/vscode/blob/8845f89c1e4183b54126cd629cd45c8f0f7549f2/src/vs/platform/native/electron-main/nativeHostMainService.ts#L491
I have created an example Electron app using this approach here: https://github.com/kmturley/electron-runas-admin
If you want to run Node.js code, you can put it inside a script.js and run:
node script.js

nodejs-dialogflow library returning TypeError: dialogflow.SessionsClient is not a constructor

I am trying to make a script that takes input from the user, runs it through Dialogflow, then returns it back to the user. The platform I am taking input from only supports Node.js. I am hosting the bot through glitch.com, but I don't think that's what's causing the issue. I wanted to check on here before I submit a bug report onto the GitHub repo.
var bot = 'the platform i use to accept inputs and send outputs'
bot.on("message", async message => {
console.log(message.content); // Log chat to console for debugging/testing
if (message.content.indexOf(config.prefix) === 0) { // Message starts with your prefix
let msg = message.content.slice(config.prefix.length); // slice of the prefix on the message
let args = msg.split(" "); // break the message into part by spaces
let cmd = args[0].toLowerCase(); // set the first word as the command in lowercase just in case
args.shift(); // delete the first word from the args
// You can find your project ID in your Dialogflow agent settings
const projectId = process.env.PROJECT_ID; //https://dialogflow.com/docs/agents#settings
const sessionId = 'quickstart-session-id';
var query = msg;
const languageCode = 'en-US';
// Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient();
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: languageCode,
},
},
};
// Send request and log result
sessionClient
.detectIntent(request)
.then(responses => {
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
})
.catch(err => {
console.error('ERROR:', err);
});
}
return;
});
That is the relevant part of the code. For those wondering, the process.env.PROJECT_ID is something glitch.com uses for anything private. Because I don't want random people getting their hands on my project id, I hide it in there and glitch hides it from anyone I don't explicitly invite.
Every time I execute this and try to query the bot, it returns an error Uncaught Promise Error: TypeError: dialogflow.SessionsClient is not a constructor.
If someone can direct me to what I'm missing, or what the problem is, that would be great!
As per #google-cloud/dialogflow - npm
IMPORTANT NOTE
Version 2.0.0 renames dialogflow to #google-cloud/dialogflow on npm, along with introducing TypeScript types.
So to update the dialogflow to use latest version, first uninstall dialogflow and then install with following command:
npm uninstall dialogflow
npm i #google-cloud/dialogflow
Also, if you were using older version 1.2.0 of dialogflow before then in code, make following changes as per their sample or refer the sample from above link (in require and to get the sessionPath):
const dialogflow = require('#google-cloud/dialogflow');
const sessionPath = sessionClient.projectAgentSessionPath(
projectId,
sessionId
);
It worked fine for me after doing this without any errors.
I figured it out. After many many refreshes, I decided to look at the npm documentation for it. Turns out some idiot listed the earliest version as 4.0.3, and the latest version as 0.7.0. I needed to explicitly tell it to use version 0.7.0 in order for it to work. Thank goodness!
Mine worked by reinstalling the dialogflow package
npm uninstall dialogflow
npm install dialogflow --save
put the code inside try and catch block. In my case by doing this, this error was removed.

Testing Node/Express API with Mocha/Chai

I am currently trying to test my node api w/ mocha chai. I am running into a scenario where a test should actually fail but is passing. I have a repo up of the current API that I am building here if you want to play around with it: enter link description here. However, I am still going to walk through the code in this question.
I'm trying to test the controller with the following code:
import chai, { expect } from 'chai';
import chaiHttp from 'chai-http';
import server from '../../src/app';
chai.use(chaiHttp);
describe('Authentication Controller', () => {
const testUser = {
email_address: 'test#test.com',
password: 'test'
};
describe('login success', () => {
it('responds with status 200', done => {
chai.request(server)
.post('/api/auth/login')
.send(testUser)
.end((err, res) => {
expect(res).to.have.status(200);
done();
});
});
});
describe('login failure', () => {
it('responds with status 401', done => {
chai.request(server)
.post('/api/auth/login')
.send(testUser.email_address = 'fake#news.com')
.end((err, res) => {
expect(res).to.have.status(200);
done();
});
});
});
});
Obviously I want to test a successful login and a failed login attempt. However, both the response statuses from the server are 200 and this should not be the case. When testing in Postman the response status when an individual tries to login with an email address that doesn't exist or a password that doesn't match, it returns a status of 401. If I write a test
expect(1).to.equal(1) => test passes.
expect(1).to.equal(2) => test fails.
Here is the controller function that handles the request for logging in:
export function login(req, res) {
User.findOne({email: req.body.email})
.then(user => {
if (user && bcrypt.compareSync(req.body.password, user.password)) {
generateToken(res, user);
} else {
res.status(401).json({
success: false,
message: 'Incorrect username or password.'
});
}
})
.catch(err => {
res.json(err);
});
}
The model that handles the request:
export function createUser(req) {
return db('users').insert(Object.assign(req.body,{password: hashPassword(req.body.password)}))
.then((id) => db('users').select().where('id', id).first());
}
As you can see I am using Knex.js. I have setup a test database and everything is connected appropriately, so I'm confused as to why my server is responding w/ a 200 response status when testing?
I just want to say thanks to anyone who takes the time to help me understand how mocha chai is working. I have very LITTLE experience with testing applications, but I want to start familiarizing myself w/ doing so because I believe it to be good practice.
I actually cloned your Github repo and tried running the test. From what I have seen, there are a couple of different issues in your code, as followed:
1. from the controller function you posted in the question:
```
export function login(req, res) {
User.findOne({email: req.body.email})
.then(user => {
// [removed because of little relevancy]
})
.catch(err => {
res.json(err);
});
}
```
The issue is the line res.json(err) which actually responded with a 200 status code (even though it was an error in this case). This is because res.json does not automatically set the HTTP response status code for you when you "send an error object". This fooled the client (in this case, chai-http) into thinking it was a successful request. To properly respond with an error status code, you may use this instead: res.status(500).json(err)
It's also worth noticing that some of your other controller functions got into this issue too.
2. from your userModels.js file, line 10, which is:
```
return db('users').select().where(req).first();
```
You are using Knex API in an incorrect way. It should be ...where('email', req.email)... This was the initial reason why your requests failed.
3. you set up your unit tests in different manners:
Test no. 1 (login success):
```
chai.request(server)
.post('/api/auth/login')
.send(testUser)
```
Test no. 2 (login failure):
```
chai.request(server)
.post('/api/auth/login')
.send(testUser.email_address = 'fake#news.com')
```
So, what happened?
In the first test, you passed an object into .send(), whereas in the second test, you simply passed an expression. When done this way, the model handler, userModels.findOne(), received an object with keys email_address and password for the first test, but for the second test, it did not.
Also, in your 1st test case, you sent testUser.email_address, but in your controller function, you referenced req.body.email.
All these, in addition to the issue no. 1 as I mentioned earlier, further complicated your test suite, leading to your misunderstanding in the end.
Disclaimer:
All what I wrote above was based on the source code from your Github repo, so if you have fixed some issues since you pushed your code, and some (or all) of my points above are no longer valid, please disregard. Nevertheless, I wish you have found, or will soon find out why your code didn't behave as you expected!
Cheers,
I just wanted to post an answer here that is specific to my experience and what helped me get all of this setup. The only thing that I really needed to change on the Repo Proj was the property email on the user object I was passing. I had email_address and was thus searching for that column in the database whilst it did not exist! So once I changed that I started down the right path.
I was then able to get my failed login test to pass. However, my successful login didn't pass. The reason was because I was seeding my database with a plain string password. Thus, when I performed the conditional statement of:
if (user && bcrypt.compareSync(req.body.password, user.password))
It wasn't passing because the bcrypt.comparSync was looking for a password that was hashed. In order to get this to work I needed to require babel-register in my knex file. This then allowed me to use es6 and perform my hashPassword function:
test/userSeed.js
import hashPassword from '../../src/helpers/hashPassword';
exports.seed = function(knex, Promise) {
return knex('users').truncate()
.then(() => {
return knex('users')
.then(() => {
return Promise.all([
// Insert seed entries
knex('users').insert([
{
first_name: 'admin',
last_name: 'admin',
email: 'admin#admin.com',
password: hashPassword('test')
},
{
first_name: 'test',
last_name: 'test',
email: 'test#test.com',
password: hashPassword('test')
}
]),
]);
});
})
};
hashPassword.js
import bcrypt from 'bcrypt';
export default function(password) {
const saltRounds = 10;
let salt = bcrypt.genSaltSync(saltRounds);
return bcrypt.hashSync(password, salt);
}
This resulted in the hashing of my users password when I seeded the DB. Tests all pass as they should and api works as intended using Postman.

NodeJS Redis Wrong # args for 'get' command

Whenever I send Redis using node_redis a get command in my nodejs app, it tells me that it has the wrong number of arguments. I've tried it with a callback and without and it always says that it's wrong.
var user = redClient.get(user);
//and
var user = redClient.get(user, function(err, result) {
if(err){
console.log(err);
}
});
I don't know if anyone cares, or I missed something in the documentation, but apparently adding redis.print as a callback to every command fixes this. Adding your own callback doesn't do anything.

Categories

Resources