I use the following code to read a file from my desktop. When I run the server and use some request I don't see anything in the debugger.
What am I missing here?
fs = require('fs');
fs.readFile('C:\Users\i123\Desktop\test.txt', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
console.log(data);
res.send(data);
});
It's hard to know all the things that might be wrong here since you only show a small piece of your code, but one thing that is wrong is the filename string. The \ character in Javascript is an escape mechanism so that the string 'C:\Users\i123\Desktop\test.txt' is not what you want it to be. If you really need backslashes in the string for a Windows filename, then you would need to use this:
'C:\\Users\\i123\\Desktop\\test.txt'
Other things I notice about your code:
Returning a value from the readFile() callback does nothing. It just returns a value back into the bowels of the async file I/O which does nothing.
When you get a file error, you aren't doing anything with the res which presumably means this route isn't doing anything and the browser will just be left waiting.
Related
I'm trying to understand how to deal(in a secure way) with Path Traversal.
For example an application receives from a client a file name via REST API in JSON, look for it in the non-accessible(by outside) directory and retrieve a response with the file:
app.get('/', (req, res) => {
const fileName = req.body.fileName;
// some code...
fs.stat(`./nonAccessibleDir/${fileName}`, async function(err, stat) {
// some code...
});
// some code...
}
The problem with the above approach is that a client can send something like "../" in the fileName request and it will "eat" it without an issue. How can one deal with this kind of scenarios, what and how I should fix this vulnerability, please?
Update:
Sorry, but I forgot to mention that I know I should check the input I receive, but what if I need to pass the "/" and "." in the input? Also, if I don't need this characters, is that all I need to check to remove the Path Traversal vulnerability?
An easy way would be to validate the fileName through a regex that detects any ../ segments and returns an error if any are present.
if (fileName.match(/\.\.\//g) !== null) {
// return an api error
}
You could have quite a tight validation rule that prevents any forward slashes in fileName at all, making it only possible to point to a file directly in your desired directory.
fs.readFileSync(process.env.id_to_name, 'utf-8', function(err, data) {
if (err) throw err;
/*
a lot of stuff
*/
fs.mkdirSync(`clips`);
fs.writeFileSync(`clips/recap.json`, '{"players":[]}', 'utf8');
});
fs.readFileSync(`clips/recap.json`, 'utf-8', function(err, data) {
var info = JSON.parse(data);
info.players.push(/* stuff */);
fs.writeFileSync(`clips/recap.json`, JSON.stringify(info), 'utf8', function (err) { });
});
I don't know what I'm doing wrong here.
The second fs.readFileSync just doesn't wait for the first one to end so it doesn't find the file he should read.
You're using fs.readFileSync() incorrectly. It does not accept a callback as an argument and does not call a callback. See doc here.
I don't know if you meant to show us fs.readFile() that does accept a callback or not.
fs.readFileSync() returns its result directly (in a synchronous fashion) from the function call as in:
let data = fs.readFileSync(someFileName, someEncoding);
It does not use a callback and it throws an exception if there's an error reading the file.
If you meant to show us an example using fs.readFile(), then it's a non-blocking, asynchronous call. If you want your second file read to wait until the first one is done, you would have to put the second file read INSIDE the completion callback of the first.
Also, please never write code like if (err) throw err; inside an asynchronous callback. That's a pointless piece of code that does nothing useful as nothing can catch that throw and you have no way to communicate back errors. It is most unfortunate that nodejs documentation shows that regularly in its examples as real world code should never do that. You will need to write real error handling where you either handle the error in some way and continue or you abort the process or you communicate back the error (probably with a callback) so the calling code can handle and see the error. Exceptions throw in asynchronous callbacks do NOT propagate back to the caller. They end up going back to the bowels of the file system code where the callback was triggered from where you cannot catch or handle them.
If you really mean to be using all synchronous calls, then you would write your code like this:
try {
let data1 = fs.readFileSync(process.env.id_to_name, 'utf-8');
// other code here
fs.mkdirSync(`clips`);
fs.writeFileSync(`clips/recap.json`, '{"players":[]}', 'utf8');
let data2 = fs.readFileSync(`clips/recap.json`, 'utf-8');
var info = JSON.parse(data2);
info.players.push(/* stuff */);
fs.writeFileSync(`clips/recap.json`, JSON.stringify(info));
} catch(err) {
// handle errors here
console.log(err);
}
Note that this code can likely only be run once without error because fs.mkdirSync('clips') will fail unless you set the recursive flag.
Hint, you can use require() to load and parse a JSON file in one step so you don't have to read it and then parse it into a Javascript object.
I easily accomplished this with the fs.readFileSync but I want to do this asynchronously. My code follows.
function send(err, str){
if(err){
console.log(err);
}
var template = ejs.render(str, 'utf8', {name: data.name});
transporter.sendMail({
from: myEmail,
to: anotherEmail,
subject: mySubject,
html: template,
attachments: images
}, function(err, response) {
if(err){
console.log(err);
}
});
}
fs.readFile('emailTemplate.ejs', send);
So I made my own callback for fs.readFile so that when the file has been read it will render the email, putting the proper name in and then send it off with nodemailer. However, it does not like this. It gets by the error if no problem but render throws the following error when it tries to render the template.
TypeError: Object (Followed by the entire HTML of the template) has no method 'indexOf'
at Object.exports.parse (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:144:21)
at exports.compile (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:229:15)
at Object.exports.render (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:289:10)
at send (/home/ubuntu/workspace/routes/email.js:171:28)
at fs.readFile (fs.js:272:14)
at Object.oncomplete (fs.js:108:15)
Doing it synchronously works fine though.
var str = fs.readFileSync('emailTemplate.ejs', 'utf8');
var template = ejs.render(str, {
name: data.name
});
Can anyone give me any insight into why this is happening?
The documentation of fs.readFile and fs.readFileSync says
If no encoding is specified, then the raw buffer is returned.
Because you provide the encoding with the synchronous version, but do not with the asynchronous one they both differ in behaviour.
If you try this:
fs.readFile('emailTemplate.ejs', {encoding: "utf8"}, send);
it should work.
Try setting the encoding of the fs.readFile call, e.g.:
fs.readFile('emailTemplate.ejs', 'utf8', send);
When calling readFile asynchronously there is no default encoding, and instead returns the raw buffer. Currently, this buffer is being sent to the EJS render call and failing.
See the node documentation for readFile for more information.
I can't figure out why this frisby tests won't run!
Basically I'm trying to import JSON from a file and check it against a return from a request. The compiler doesn't seem to find any tests when I run this file.
If anyone could possibly suggest a better way to do this? I'm thinking about trying a different way to handle the file reading. I know about readFileSync() but I do not want to use that if I don't have to! Any help would be appreciated.
function readContent(callback,url,file) {
fs.readFile(file, 'UTF8', function (err, content) {
if (err) return callback(err)
data = JSON.parse(content)
callback(null, data)
})
}
readContent(function (err, content) {
frisby.create('Testing API')
.get(url)
.expectStatus(200)
.expectBodyContains(content)
.toss()
},
url,file)
Here's one I prepared earlier:
// Read a JSON file from disk, and compare its contents with what comes back from the API.
fs.readFile(path.resolve(__dirname, 'GET_ReferenceTypes.json'), 'utf-8', function(error, data){
if (error) throw error
frisby.create('GET ReferenceTypes, inside readFile callback')
.get(URL + 'ReferenceTypes?requestPersonId=2967&id=99')
.expectStatus(200)
// JSON.parse() is required to convert the string into a proper JSON object for comparison.
// The .replace() strips the BOM character from the beginning of the unicode file.
.expectJSON(JSON.parse(data.replace(/^\uFEFF/, '')))
.toss();
});
Double check the encoding on your JSON file, because this whole thing comes apart without the .replace() call.
I am new to node.js .Here I write a sample function in node.js to print the contents of a json file as follows.
exports.getData =function(callback) {
readJSONFile("Conf.json", function (err, json) {
if(err) { throw err; }
console.log(json);
});
console.log("Server running on the port 9090");
What I am doing here is I just want to read a json file and print the contents in console. But I do not know how to call the getData function. While running this code it only prints the sever running on the port..", not myjson` contents.
I know the above code is not correct
How can I call a function in node.js and print the json contents?
Node.js is just regular javascript. First off, it seems like you are missing a }. Since it makes the question easier to understand, I will assume that your console.log("Server... is outside exports.getData.
You would just call your function like any other:
...
console.log("Server running on the port 9090");
exports.getData();
I would note that you have a callback argument in your getData function but you are not calling it. Perhaps it is meant to be called like so:
exports.getData = function(callback) {
readJSONFile("Conf.json", function (err, json) {
if(err) { throw err; }
callback(json);
});
}
console.log("Server running on the port 9090");
exports.getData(function (json) {
console.log(json);
});
Truthfully, your getData function is a little redundant without any more content to it since it does nothing more than just wrap readJSONFile.
Don't take this the wrong way, but your code appears to be a mixed up mess of unrelated examples. I recommend you start by learning the basics of JavaScript and node.js (for example, read Eloquent JavaScript and Felix's Node.js Beginners Guide).
But on to your code. First of all, you are creating a function (called getData) and exporting it. Then you're printing "Server running on the port 9090". There is no server code in your script, and the function you created is never executed.
I think this is what you intended to write:
readJSONFile("Conf.json", function (err, json) {
if(err) { throw err; }
console.log(json);
});
Assuming that readJSONFile is a real function.