How to get caller ip in node.js + express? - javascript

In a node.js with express I'd like to define a footer such as (in layout.jade)
footer
p © Me 2015 - Your IP: #{currentIP}
in app.js, I have:
app.locals.currentIP = function(req) {
return req.ip;
}
When run I get the following error:
> 29| block content 30| footer
> > 31| p © Me 2015 - Your IP: #{currentIP()} 32| 33| script(
> src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js'
> ) 34| script( src='javascripts/bootstrap.js' )
>
> Cannot read property 'url' of undefined at app.locals.currentIP
> (c:\workspaces\nodejs.workspace\express_website\app.js:66:13) at
> eval (eval at <anonymous>
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:218:8),
> <anonymous>:199:69) at eval (eval at <anonymous>
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:218:8),
> <anonymous>:225:22) at res
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:219:38)
> at Object.exports.renderFile
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:380:38)
> at Object.exports.renderFile
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:370:21)
> at View.exports.__express [as engine]
> (c:\workspaces\nodejs.workspace\express_website\node_modules\jade\lib\index.js:417:11)
> at View.render
> (c:\workspaces\nodejs.workspace\express_website\node_modules\express\lib\view.js:126:8)
> at tryRender
> (c:\workspaces\nodejs.workspace\express_website\node_modules\express\lib\application.js:639:10)
> at EventEmitter.render
> (c:\workspaces\nodejs.workspace\express_website\node_modules\express\lib\application.js:591:3)
What's wrong?

According to official doc
app.locals properties persist throughout the life of the application,
in contrast with res.locals properties that are valid only for the
lifetime of the request.
In your case it would be better to use res.locals.currentIP instead app.locals.currentIP because lifetime of ip is bound to request rather than application life cycle:
To pass a current user's ip to a view just use:
app.post('/get/ip/address', function (req, res) {
res.locals.currentIP = req.ip
...
});
In a view you have to use the following snippet to output an accepted ip address.
footer
p © Me 2015 - Your IP: #{locals.currentIP}
The error Cannot read property url of undefined at app.locals.currentIP due to your currentIP() fucntion get executes in another context. My suggestion is don't use function for outputting current user's ip but use scalar value as my code above shows.
You could reside res.locals.currentIP in a middleware to get access to currentIP variable in all of your views like the following:
var express = require('express');
var app = express();
app.enable('trust proxy');
app.use(express.static(__dirname + '/public'));
app.use(fucntion (req, res, next) {
res.locals.currentIP = req.ip;
next();
});
// routes does after the middleware !
// ...
app.listen(process.env.PORT || 3000);
Note that your route definitions should be after the middleware that populates res.locals.currentIP.

Related

Variable not getting passed to Pug

I am creating an express.js app as part of a team project. I'm a javascipt novice, but the task ultimately fell to me. The purpose of the relevant code is to run a script when a button is clicked, using some user-defined options, then show a new page and display links for the reports that have been generated on a results page. For whatever reason, this never works the first time after the app is started, but it will work if you go back and try again. I had thought there was a synchronization issue, and there might be, but there also seems to be an issue with the array variables not being passed to pug. I've been slamming my head against the desk to this for weeks, and asked for assistance from my professor (neither of us are CS people) with no luck. Please help.
Here's the app variables, configuration, etc. at the beginning of the file:
// index.js
/**
* Required External Modules
*/
const express = require("express");
const path = require("path");
const shell = require("shelljs");
const fs = require("fs");
/**
* App Variables
*/
const app = express();
const port = process.env.PORT || "8000";
var ipAddresses;
var ipAddressesLink;
/**
* App Configuration
*/
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
app.use(express.static(path.join(__dirname, "public")));
app.use(express.static(path.join(__dirname, "reports/html")));
//code to make html forms work
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
Here's the relevant route that keeps failing me:
//Run script when post is rec'd from root and send to results page
app.post("/", (req, res) => {
//take values and create complete command for Astrum script
var commandString = 'bash /home/astrum/Main/Astrum.sh -s ' + req.body.speed + ' -h ' + req.body.host + ' -u ' + req.body.username + ' -p ' + req.body.password;
var pathToReports = './reports/html';
runScript(commandString);
readFolder(pathToReports);
renderPage();
//Iterate thru filenames to create arrays for links and link labels
function readFolder(pathValue) {
fs.readdir(pathValue, (err, files) => {
console.log(files)
//variable & method for links to html records pages
ipAddressesLink = files;
console.log(ipAddressesLink);
//variable and method to remove file extension for link labels in pug
ipAddresses = files.map(removeExtension);
});
}
//function to remove last five characters of each element
function removeExtension(value) {
return value.substring(0, value.length - 5);
};
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
//function to execute command in shell
function runScript(value) {
shell.exec(value);
}
//show array on console for debugging
console.log("type of record is: " + typeof ipAddressesLink);
console.log(ipAddressesLink);
console.log(ipAddresses);
res.end();
});
Here is the pug template for the results page which is throwing the error, obviously a work in progress:
extends layout
block layout-content
div.View
div.Message
div.Title
h1 Astrum Network Analysis
div.Body
div.multiple-group
h3 Heading
select(id='whitelist', name='whitelist' size='6' multiple)
option(value="volvo") Volvo
option(value="saab") Saab
option(value="fiat") Fiat
option(value="audi") Audi
option(value="bmw") BMW
div.form-group
label(for='whitelistButton')
input(type='submit' value='Whitelist Ports')
h3 Hosts Found:
ul
each val, index in ipAddressesLink
li: a( href = val ) #{ipAddresses[index]}
And here's the error message I get:
TypeError: /home/astrum/Main/astrumApp/views/results.pug:36
34| ul
35|
> 36| each val, index in ipAddressesLink
37|
38| li: a( href = val ) #{ipAddresses[index]}
39|
Cannot read property 'length' of undefined
at eval (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:93:32)
at eval (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:116:4)
at template (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:119:7)
at Object.exports.renderFile (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:452:38)
at Object.exports.renderFile (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:442:21)
at View.exports.__express [as engine] (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:491:11)
at View.render (/home/astrum/Main/astrumApp/node_modules/express/lib/view.js:135:8)
at tryRender (/home/astrum/Main/astrumApp/node_modules/express/lib/application.js:640:10)
at Function.render (/home/astrum/Main/astrumApp/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/home/astrum/Main/astrumApp/node_modules/express/lib/response.js:1012:7)
You should use fs.readdirSync! I'm sure fs.readdir in readFolder function is running out of your expected process order:
function readFolder(pathValue) {
//variable & method for links to html records pages
ipAddressesLink = fs.readdirSync(pathValue);
//variable and method to remove file extension for link labels in pug
ipAddresses = ipAddressesLink.map(removeExtension);
}
Try changing:
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
to:
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink: ipAddressesLink, ipAddresses: ipAddresses, title: 'Results'});
}

How to fix 'ERROR _HTTP_INVALID_STATUS_CODE' in Node?

I got some error and I have no Idea what does It mean any ideas, please?
This is the error:
I have no idea what is going on because I never got the error like that before and I am using res.redirect same way as always. I found out that you should use res. render, but I want to be redirected to a page not to render the page...
> Sun, 10 Feb 2019 18:47:15 GMT express deprecated res.redirect(url,
> status): Use res.redirect(status, url) instead at
> routes\placeorder.js:50:17 RangeError [ERR_HTTP_INVALID_STATUS_CODE]:
> Invalid status code: [object Object]
> at ServerResponse.writeHead (_http_server.js:208:11)
> at ServerResponse.writeHead (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\on-headers\index.js:55:19)
> at ServerResponse.writeHead (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\on-headers\index.js:55:19)
> at ServerResponse._implicitHeader (_http_server.js:199:8)
> at write_ (_http_outgoing.js:585:9)
> at ServerResponse.write (_http_outgoing.js:567:10)
> at writetop (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\express-session\index.js:290:26)
> at ServerResponse.end (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\express-session\index.js:351:16)
> at ServerResponse.redirect (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\express\lib\response.js:947:10)
> at putOrderToDBAndRedirect (C:\Users\Petr\WebstormProjects\BakalarskaPrace\routes\placeorder.js:50:17)
> _http_server.js:208
> throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode);
> ^
>
> RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code:
> [object Object]
> at ServerResponse.writeHead (_http_server.js:208:11)
> at ServerResponse.writeHead (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\on-headers\index.js:55:19)
> at ServerResponse.writeHead (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\on-headers\index.js:55:19)
> at ServerResponse._implicitHeader (_http_server.js:199:8)
> at write_ (_http_outgoing.js:585:9)
> at ServerResponse.end (_http_outgoing.js:709:5)
> at writeend (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\express-session\index.js:261:22)
> at Immediate.ontouch (C:\Users\Petr\WebstormProjects\BakalarskaPrace\node_modules\express-session\index.js:348:11)
> at processImmediate (timers.js:632:19)
>
> Process finished with exit code 1
const putOrderToDBAndRedirect = async(res,userId,serviceObj,
ordStart,ordEnd) =>{
try{
const result = await pool.query('SELECT id ' +
'FROM orders ' +
'WHERE ($1,$2) OVERLAPS (ord_start,ord_end)',
[ordStart,ordEnd]);
if(isOverlaping(result)){
console.log('redirect to page with orders');
res.redirect('/objednat')
}else{
await pool.query('INSERT INTO orders (ord_entered,ord_start,user_id,service_id,ord_end)' +
' VALUES($1,$2,$3,$4,$5)',
[new Date(),ordStart,userId,serviceObj.id,ordEnd]);
const resultArr = await pool.query('SELECT firstname,lastname,phonenumber ' +
'FROM users ' +
'WHERE ' +
'id = $1',[userId]);
console.log(resultArr.rows[0]);
const obj = constructOrderObj(serviceObj,ordStart,resultArr.rows[0]);
res.redirect('/objednano',{orderObj:obj});
}
}catch(err){
console.error(err);
}
};
You're calling res.redirect('/objednano',{orderObj:obj}); but that does not match the function signature for res.redirect() which takes an optional status as the first argument and the path as the second argument (or the path as the first argument if there is only one argument, in which case status will default to 302).
It's unclear to me what you're trying to do there, to be honest. But that line is the problem. It's treating the first argument as the status code, and '/objednano' is obviously an invalid HTTP status. So the error message is complaining that the HTTP status is invalid.
If you use res.redirect to send the response to the client, it will have a status code of 302 (which basically is a redirect) means that the the current data that you need is not available in the current location, but in another location as redirected
If you are trying to get this resource from a frontend app or client (like using fetch or XMLHTTPresponse, then you might get such an error)
The best possible way is to explicitly tell express (or the response object) that you are trying to send a json response for this request

problem when passing a callback in a res.render ()

I'm doing a small application bringing some data from some remote JSON files and the idea is to generate some statistics that are later printed in an EJS file.
I want to pass separately values ​​to render and then use them in the document ejs.
The server file works well, apart from that I have a module in which I develop the functions and a script where I have the routes and execute them:
//rapi.js
const extjson = require ('remote-json');
//---------------------API CONFIG--------------------------
//apikey
const apikey ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
function get_sum_id(sumname, callback){
const urlsumbySumName = "https://la2.api.riotgames.com/lol/summoner/v3/summoners/by-name/" + sumname + "?api_key=" + apikey;
extjson(urlsumbySumName).get(callback);
}
function get_league_data(sumid, callback){
const urlgetleaguedata ="https://la2.api.riotgames.com/lol/league/v3/positions/by-summoner/"+ sumid + "?api_key="+ apikey;
extjson(urlgetleaguedata).get(callback)
}
module.exports = { get_sum_id, get_league_data};
//---------------------------------------------------------------------
//index.js
const riot = require('./rapi.js');
const express = require('express');
const router = express.Router();
router.get('/',async (req, res) => {
res.render('index');
});
router.post('/profile',async (req, res, next)=>{
const sum = req.body.summoners; //from html form
const sum_id = riot.get_sum_id(sum, function(err, resp, body){body.id});
res.render('profile', {sum,
id: sum_id,
league: riot.get_league_data(sum_id, function(err,resp,body){body})
});
});
module.exports = router;
what I want to do as seen there is to pass the value of that callback directly to the render and reference it. Obviously something I'm doing wrong since it does not work.
outputs:
> in localhost:3000/profile - internal server error. in console:
> TypeError:
> C:\xampp\htdocs\proyectos\legendsop\src\views\profile.ejs:80
> 78| <section class="row border">
> 79| <section class="col-2 border">Perfil</section>
> >> 80| <section class="col-1 border">SOLO/DUO Q <br><%= league[1].tier%></section>
> 81| <section class="col-1 border">FLEX <br><%= league[0].tier%></section>
> 82| <section class="col-4 border">WinRateRolCola</section>
> 83| <section class="col-2 border">EstadisticasCampeones</section>
>
> Cannot read property '1' of undefined
>
> at eval (eval at compile (C:\xampp\htdocs\proyectos\legendsop\node_modules\ejs\lib\ejs.js:618:12),
> <anonymous>:16:32)
> at returnedFn (C:\xampp\htdocs\proyectos\legendsop\node_modules\ejs\lib\ejs.js:653:17)
> at tryHandleCache (C:\xampp\htdocs\proyectos\legendsop\node_modules\ejs\lib\ejs.js:251:36)
> at View.exports.renderFile [as engine] (C:\xampp\htdocs\proyectos\legendsop\node_modules\ejs\lib\ejs.js:482:10)
> at View.render (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\view.js:135:8)
> at tryRender (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\application.js:640:10)
> at Function.render (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\application.js:592:3)
> at ServerResponse.render (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\response.js:1008:7)
> at router.post (C:\xampp\htdocs\proyectos\legendsop\src\routes\index.js:14:5)
> at Layer.handle [as handle_request] (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\layer.js:95:5)
> at next (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\route.js:137:13)
> at Route.dispatch (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\route.js:112:3)
> at Layer.handle [as handle_request] (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\layer.js:95:5)
> at C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\index.js:281:22
> at Function.process_params (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\index.js:335:12)
> at next (C:\xampp\htdocs\proyectos\legendsop\node_modules\express\lib\router\index.js:275:10)
>
> Git GitHub Initialize a new project directory with a Git repository
> Create repository
Excuse me if my English is not understood very well I am Spanish speaking.
This might help you
The purpose of the res.render callback argument
Render the ejs file in callback again
hope this helps
cheers

Kue crashes parse server

I'm trying to use kue for scheduled jobs on my Parse Server (hosted on heroku). For now I've modified my index.js file like so as stated in the several tutorials I found about Kue :
var express = require('express')
, kue = require('due')
, redis = require('redis');
var ParseServer = require('parse-server').ParseServer;
var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '',
serverURL: process.env.SERVER_URL
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
// connect to REDIS
var client = redis.createClient(process.env.REDIS_URL);
var app = express();
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api)
.use(kue.app); // wire up Kue (see /active for queue interface)
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a web site.');
});
var port = process.env.PORT || 1337;
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
I've found out that the app crashes at the line : .use(kue.app). Here is the error I get :
Starting process with command `node index.js`
parse-server-example running on port 22995.
/app/node_modules/parse-server/lib/index.js:298
throw err;
^
Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379
at Object.exports._errnoException (util.js:890:11)
at exports._exceptionWithHostPort (util.js:913:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1057:14)
Process exited with status 7
State changed from starting to crashed
I don't know why this is happening.
The line : .use(ku.app) can be removed. And all that is needed is to add :
var jobs = kue.createQueue({ redis: process.env.REDIS_URL })
to access the current queue.
Hope it'll helps somebody.

Getting a csrf token in a form

This open source chat project https://github.com/meatspaces/meatspace-chat uses the jade index file below. You'll notice that the form has an input value for a #{csrf} token. Where would this csrf value be coming from? Is it part of the browser environment? I don't see any javascript in the project that inserts that csrf token into that input field.
For example, when you visit the root, it just renders the index like this
app.get('/', function (req, res) {
res.render('index');
});
index
extend layout
block content
form(method='post', id='add-chat-form')
input(type='hidden', name='picture', id='picture')
.message-content
input(name='message', id='add-chat', class='input', maxlength='250', autocomplete='off', placeholder='Send a public message')
input(type='hidden', name='_csrf', value='#{csrf}')
input(type='hidden', name='fingerprint', id='fp')
input(type='hidden', name='userid', id='userid')
#add-chat-blocker.hidden
span Sending, please wait!
#counter 250
The tokens are created by the connect csrf middleware. You can see this in settings.js. On line 7:
var csrf = express.csrf();
and line 13:
var clientBypassCSRF = function (req, res, next) {
if (req.body.apiKey && nativeClients.indexOf(req.body.apiKey) > -1) {
next();
} else {
csrf(req, res, next);
}
};
This exposes a function csrfToken on the req object, which is used on line 45:
res.locals.csrf = req.csrfToken();
The express templating engine (res.render('index'); in the code you showed in your question) extends the templates scope with the res.locals object, which is how that field gets filled in during templating.

Categories