I developed a small web application using Node.js. The core part of the server is:
var http = require('http');
var https = require("https");
var privateKey = fs.readFileSync("sslcert/server.key", "utf8");
var certificate = fs.readFileSync("sslcert/server.crt", "utf8");
var credentials = { key: privateKey, cert: certificate};
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
httpServer.listen(80);
httpsServer.listen(443);
...
var app = express();
var routes = require('./routes/index');
app.use(function https(req, res, next){
if (!req.secure) return res.redirect("https://" + req.headers.host + req.url);
next();
});
app.use('/', routes);
...
var router = express.Router();
router.get("/", function (req, res, next) {
res.render("index");
});
It works and also redirect the incoming http connections to the https server.
With Chrome for Android, sometimes (I didn't find any criteria) it doesn't load anything (i.e. no activity is shown on the server logs) or it partially loads a page - no errors though. In both case the browser shows a blank page. Refreshing multiple times ofter leads to a normal loading. In few cases I had to exit and run again Chrome.
With Firefox for Android, it always works.
I'm afraid there are some differences between browsers I'm not aware of.
Where should I look? At the Node.js server code, or in the main "index" view?
Currently I'm testing the server in LAN.
UPDATE
After debugging a bit I found that there are errors in the console when the page is not loaded (it makes sense, indeed!).
Uncaught Error: undefinedModule
at _f (https://192.168.178.53/javascripts/dojo/dojo.js:8:436)
at _16 (https://192.168.178.53/javascripts/dojo/dojo.js:8:7573)
at req (https://192.168.178.53/javascripts/dojo/dojo.js:8:555)
at _9 (https://192.168.178.53/javascripts/dojox/mobile/parser.js:11:42)
at _7.parse (https://192.168.178.53/javascripts/dojox/mobile/parser.js:102:4)
at https://192.168.178.53/:66:12
at _ce (https://192.168.178.53/javascripts/dojo/dojo.js:8:11949)
at _37 (https://192.168.178.53/javascripts/dojo/dojo.js:8:13569)
at https://192.168.178.53/javascripts/dojo/dojo.js:8:13833
at _38 (https://192.168.178.53/javascripts/dojo/dojo.js:8:13659)
and
Uncaught TypeError: Cannot read property 'set' of undefined
at https://192.168.178.53/:315:33
at _ce (https://192.168.178.53/javascripts/dojo/dojo.js:8:11949)
at _37 (https://192.168.178.53/javascripts/dojo/dojo.js:8:13569)
at https://192.168.178.53/javascripts/dojo/dojo.js:8:13833
at _38 (https://192.168.178.53/javascripts/dojo/dojo.js:8:13659)
at _81 (https://192.168.178.53/javascripts/dojo/dojo.js:8:13758)
at _f6 (https://192.168.178.53/javascripts/dojo/dojo.js:8:15537)
at HTMLScriptElement._10b (https://192.168.178.53/javascripts/dojo/dojo.js:8:18464)
The only references to my code are at line 66 and line 315.
Line 66 is just the parser invocation in the head section:
require([
"dojox/mobile/parser",
"dojox/mobile/View",
"dojox/mobile/Button",
"dojox/mobile/TextBox",
"dojox/mobile/RoundRect",
"dojox/mobile/FilteredListMixin",
"dojox/mobile/TextArea",
"dojox/mobile/Switch",
"dojox/mobile/FormLayout",
"dojox/mobile/SimpleDialog",
"dojo/domReady!"
], function (parser) {
parser.parse();
});
while line 315 is included in this short snippet, executed on startup:
var userName = JSON.parse(localStorage.getItem("userName"));
if (userName != undefined && userName.length) {
registry.byId("txtName").set("value", userName); // line 315
}
As far I as understand the console error is saying it "cannot read property (?!) set of undefined". Set is a method anyway.
I guess it doesn't find the txtName widget. It is defined as:
input#txtName.login(type="text" data-dojo-type="dojox/mobile/TextBox" data-dojo-props="selectOnClick:true, placeHolder:'Username'" name="name" required)
and the snippet above as dojo/domReady! as last item of the require array.
It appears weird to me because FireFox doesn't throw such errors.
Do you see any evidence of wrong code here?
Related
I am on a school Chromebook, where developer tools are disabled. I sometimes coded on node.js, having server-side and client-side code. But, as developer tools are disabled, I can't check errors on the client-side, as to only find that it sometimes just stops working without a clue as to what is wrong. I have had this issue a whole lot whenever coding client-side code.
How could I detect and identify the error with only access visually to the node.js console, as well as express and socket.io?
For example,
const express=require("express");
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
app.use(
'/client',
express.static(__dirname + '/client')
);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/client/index.html');
console.log("sending site");
});
http.listen(3000, () => {
console.log('listening on *:3000 (http.listen)');
});
io.on('connection', (socket) => {
socket.emit("ERRORNOW",26);
});
//"<script src="/socket.io/socket.io.js"></script>" assumed to be in HTML file
var socket=io();
socket.on("ERRORNOW",()=>{
if("this doesnt have an ending curlybracket){
//}
//this is the error it doesnt have the ending curly bracket,
//but it doesn't show in the node.js console
//(at least on browser IDEs like repl.it),
//and debugging without the developer tools
//can be infuriating to say the least
});
The question is How can I identify a node.js client-side error on a web-based IDE without developer tools?
I have already had this issue a while ago, and due to the lack of developer tools on school Chromebooks, found the solution on my own, but I just thought that maybe I should also put it here.
My solution, as simple as it may be, is to just use a try-catch statement and send the error to the node.js console. It took a while to figure that out...
So, if you don't already have it, you would need a function that when triggered from the client side can log something into the console, inside of the io.on("connection",()=>{}); thing, like so:
io.on("connection",()=>{
socket.on("log", input=>{
console.log(input);
});
});
For example, if everything runs off of a single function that is triggered really fast (specific, but relevant to me, as I make web games), or just off of something, you can run it off of a function inside a try catch, like so:
//"<script src="/socket.io/socket.io.js"></script>" assumed to be in HTML file
var socket=io();
try{
socket.on("ERRORNOW",()=>{
try{
if("this doesnt have an ending curlybracket){
//}
}catch(error){
socket.emit("log",error);
}
});
}catch(error){
socket.emit("log",error);
}
So now, with this simple solution, you can stop commenting out 90% of your code to find that one error that makes it stop working while breaking it further by accidentally commenting out parts that help it to work in the first place!
I am trying to fix the Checkmarx scanning tool reported issue, I tried to sanitized the err as well as req in the below route module.
However, it still complains about the same error.
index.js
const express = require('express')
const router = express.Router()
const fs = require('fs')
const config = require('config')
var _require = require('jsdom'),
JSDOM = _require.JSDOM;
var window = new JSDOM('').window;
var DOMPurify = createDOMPurify(window);
function sanitizeError(value){
return DOMPurify.sanitize(value);
}
function sanitizeObject(obj) {
var sanitizedObject = {};
Object.keys(obj).forEach(function (key) {
sanitizedObject[key] = sanitizeValue(obj[key]);
});
return sanitizedObject;
};
//error handler route
router.use('/error',(err, req, res, next) => {
//sanitizeObject(req)
req.logger.error('uncaught error page', sanitizeError(err))
res.redirect('/toanotehrerror page')
})
module.exports = router
Checkmarx Error:
Reflected_XSS error. It is referring to the line req.logger.error in the above module
The application's router.use embeds untrusted data in the generated output with error, at line x of \routes\index.js. This untrusted data is embedded straight into the output without proper sanitization or encoding, enabling an attacker to inject malicious code into the output.
The attacker would be able to alter the returned web page by simply providing modified data in the user input error, which is read by the router.use method at line x of \routes\index.js. This input then flows through the code straight to the output web page, without sanitization.
This can enable a Reflected Cross-Site Scripting (XSS) attack.
Checkmarx does not have DOMPurify in the list of its recognized sanitizers. What it does recognize are the ESAPI library, xss-filters and htmlescape packages
https://www.npmjs.com/package/xss-filters
https://www.npmjs.com/package/node-esapi
https://www.npmjs.com/package/htmlescape
While technically your code can prevent XSS, I would rewrite it using using any of the packages above. For instance if we are to use xss-filters:
var xssFilters = require('xss-filters');
function sanitizeError(value){
return xssFilters.inHTMLData(value);
}
I am trying to use Actions SDK in my own Server, the actions that I made are showed in Google Assistant, but it's not working, the assistant just closes without showing any errors. This is my code:
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
var exps = express();
exps.use(bodyParser.json());
const {actionssdk} = require('actions-on-google');
const app = actionssdk({debug: true});
const asyncTask = () => new Promise(
resolve => setTimeout(resolve, 1000)
);
exps.post('/', function(request, response) {
app.intent('actions.intent.MAIN', (conv) => {
return asyncTask()
.then(() => conv.ask('Hi, this is a test!'));
});
});
express().use(bodyParser.json(), app).listen(3000);
Request and Debug tabs
Both Errors and Response are empty.
I think the issue is that you are creating two different express objects. One gets mounted on the '/' path, but isn't setup to listen on any port. The other listens on a port, but doesn't have any paths setup for it to handle.
Changing your listener line to
exps.use(bodyParser.json(), app).listen(3000);
will make it so the express object where you've setup the '/' path will also be the one listening on the port.
It also appears that your webhook is listening at the '/' path, but you've specified the webhook in your actions.json file as using the '/node/' path. (It is a little difficult to read the screen shot - which is why we request you post the text and not a screen shot.) If you either change your webhook to listen to '/node/' or change the actions.json file to use '/', it should work.
Looking at the documentation (https://developers.google.com/actions/assistant/responses) suggests that you are attempting to call conv.ask() incorrectly. I would imagine you'd need something like this:
conv.ask(new SimpleResponse({speech: 'Hi, this is a test!', text: 'Hi, this is a test!'}));
I'm trying to create a webapp for a web art class using node (w/ npm) and express. The idea is to have the body of the site be all one color, but anyone can text the site a hexcode/CSS color at a Twilio number and the color of the site will instantly change to that color value.
Essentially how it works is the server receives a POST request from Twilio at http://example.com/message, which contains the body of the text message. It writes it to a temporary file at ~/app/.data/color.tmp, which is accessed by the client with a jQuery .get() call to http://example.com/color, which returns
So here's the problem: I got a version of the app working on glitch.me, so I know that this code can work, but I'm having a lot of trouble getting it to work on my domain. I installed the app and can start it with npm, and it successfully shows me the HTML page, but the Chrome devtools show the script is receiving a 403 when it tries to access /color. Also, new texts to my site aren't changing the color value in /.data/color.tmp. I thought it might be a permissions issue but I checked them and they seem fine.
Here's the server file and the script on the index.html page:
app/server.js
var express = require('express');
var bodyParser = require('body-parser');
var fs = require('fs');
var app = express();
app.use(bodyParser.urlencoded({extended: false}));
var dataPath = '.data/color.tmp';
// set a new color (saves posted color to disk)
app.post("/message", function (request, response) {
var dataStr = JSON.stringify(request.body.Body);
fs.writeFile(dataPath, dataStr);
response.end();
});
// get the saved color (reading from disk)
app.get("/color", function (request, response) {
var dataStr = fs.readFileSync(dataPath).toString();
response.send(JSON.parse(dataStr));
});
app.get("/", function (request, response) {
response.sendFile(__dirname + '/views/index.html');
});
var listener = app.listen(process.env.PORT, function () {
console.log('listening on port ' + listener.address().port);
});
app/views/index.html
<script>
// checks server for color value and sets background
function checkForColorChange() {
$.get('/color', function getColorComplete(data) {
document.body.style.backgroundColor = data;
console.log(data);
})
}
// Poll the server at 2000ms interval
setInterval(checkForColorChange, 2000);
checkForColorChange();
</script>
Anyway, I feel like I must be missing something really obvious if it worked so easily on Glitch and won't on my website, but I've been stuck for a few days and am not making any progress! Any help would be so appreciated. Let me know if anything's unclear too.
(See update below for a working example)
TL;DR - example:
Original answer
There are few problems with your code:
you're not checking for errors
you're using blocking functions
you're implicitly relying on file permissions but you're not checking it
you're using string concatenation instead of path.join to join paths
you're constantly polling for new data instead of waiting for it to change
you're not catching exceptions of functions that can raise exception
you're not waiting for async operations to finish and you don't handle errors
The main problem that you're experiencing right now is most likely with the file permissions. The good news is that you don't need any file access for what you're doing and using files for that is not optimal anyway. All you need is to store the color in a variable if you don't need it it persist between server restarts - and even if you do then I would use a simple database for that.
For example:
// some initial value:
var color = '#ffffff';
app.post("/message", function (request, response) {
var color = request.body.Body;
response.end();
});
// get the saved color (reading from disk)
app.get("/color", function (request, response) {
response.send(color);
});
app.get("/", function (request, response) {
response.sendFile(__dirname + '/views/index.html');
});
var listener = app.listen(process.env.PORT, function () {
console.log('listening on port ' + listener.address().port);
});
This is the first change that I would use - don't rely on the file system, permissions, race conditions etc.
Another problem that you had with your code was using blocking functions inside of request handlers. You should never use any blocking function (those with "Sync" in their name) except the first tick of the event loop.
Another improvement that I would make would be using WebSocket or Socket.io instead of polling for data on regular intervals. This would be quite easy to code. See this answer for examples:
Differences between socket.io and websockets
A plus of doing that would be that all of your students would get the color changed instantly and at the same time instead of in random moments spanning 2 seconds.
Update
I wrote an example of what I was describing above.
The POST endpoint is slightly different - it uses /color route and color=#abcdef instead of /message and Body=... but you can easily change it if you want - see below.
Server code - server.js:
// requires removed for brevity
const app = express();
const server = http.Server(app);
const io = socket(server);
let color = '#ffffff';
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/', express.static(path.join(__dirname, 'html')));
io.on('connection', (s) => {
console.log('Socket.io client connected');
s.emit('color', color);
});
app.post('/color', (req, res) => {
color = req.body.color;
console.log('Changing color to', color);
io.emit('color', color);
res.send({ color });
});
server.listen(3338, () => console.log('Listening on 3338'));
HTML page - index.html:
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>Node Live Color</title>
<link href="/style.css" rel=stylesheet>
</head>
<body>
<h1>Node Live Color</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="/script.js"></script>
</body>
</html>
Style sheet - style.css:
body {
transition: background-color 2s ease;
background-color: #fff;
}
Client-side JavaScript - script.js:
var s = io();
s.on('color', function (color) {
document.body.style.backgroundColor = color;
});
What is particularly interesting is how simple is the client side code.
For your original endpoint use this in server.js:
app.post('/message', (req, res) => {
color = req.body.Body;
console.log('Changing color to', color);
io.emit('color', color);
res.end();
});
Full example is available on GitHub:
https://github.com/rsp/node-live-color
I tested it locally and on Heroku. You can click this button to deploy it on Heroku and test yourself:
Enjoy.
I think, the problem is in var dataStr = fs.readFileSync(dataPath).toString();. Please change your dataPath as follow:
var dataPath = __dirname + '/data/color.tmp';
And also make sure that file has read/write permission by the .
I am actually facing an issue here. I am having a login page From there I am going to another page. From there I am getting my socket disconnected.
What i am trying to do is
In my server side app.js
app.post('/login', urlencodedParser, function(req, res) {
req.session.username = req.body.usr;
req.session.password = req.body.pass;
req.session.password = 380;
authenticatAPI.logIn(req, res);
});
From here then to authenticate js(server side)
getUserName = req.body.usr;
getPassword = req.body.pass;
req.session.username = getUserName;
req.session.password = getPassword;
res.send({url:"screen1.html",id:100,usr:getUserName});
From here to client side
var socket = io.connect('http://localhost:8080');
When i reach here Again it goes for app.js and goes inside the io.on("connection") function ,here I am getting an error when i debug using node inspect.
"Remote debugging stopped Websocket closed reattach new target"
What should i do here....?
I'm going to bet that you have node inspect set to break on caught exceptions. Try unchecking "Pause On Caught Exceptions" near the right hand side of the debugger.
Otherwise, you are likely using a 3rd party library that is using socket.io that is throwing this error.