Custom validator on object in express-validation - javascript

Issue
Custom validator not giving any response. I want to validate this below object in express-validator. The privilege key must be valid and exist in my array. If privilege object does not exist then the validation not working because it's optional but the value must be valid if the object exists
{
"email" : "john#gmail.com",
"privileges" : {
"topic" : true
}
}
user.js
const User = require('../../models/User');
const { check, validationResult } = require('express-validator');
let privilegesArray = ['topic'];
router.post(
'/',
[
check("privileges")
.custom(async (value, { req }) => {
Object.keys(value).forEach(function(key){
if(!privilegesArray.includes(key)){
return false;
}
if(value[key] === 'true' || value[key] === 'false' || value[key] === ''){
return false;
}
})
}).withMessage("Invalid privileges").optional({checkFalsy: true})
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
}
);
I am a beginner in node-js and not using any custom validator.

Okay, so there are few problems with your script:
Within the custom handler, you are iterating using forEach:
Object.keys(value).forEach(function(key){
if(!privilegesArray.includes(key)){
return false;
the problem is, however, that you are returning false from within the internal forEach handler, not the custom handler itself.
You shouldn't be returning by the way, according to documentation. You should throw an error instead.
You didn't provide handler if everything goes well, eg. return res.status(200).json({ errors: "[]" }); in case everything goes fine in route handler.
Most important I guess, you didn't register any bodyParser. I'm pretty sure express won't be able to understand application/json in the POST body: app.use(bodyParser.json());
After middleware parses input jsons, you shouldn't be comparing value[key] === 'true', as it's going to be boolean true.
Below is complete code which seems to meet your requirements, tested using fiddler:
const { check, validationResult } = require("express-validator");
const bodyParser = require("body-parser");
const express = require("express");
const app = express();
const port = 3000;
let privilegesArray = ["topic"];
app.use(bodyParser.json());
app.post(
"/",
[
check("privileges")
.custom(async (value, { req }) => {
var keys = Object.keys(value);
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
if (!privilegesArray.includes(key)) continue;
if (
value[key] !== true &&
value[key] !== false &&
value[key] !== ""
) {
throw new Error("Topic is invalid.");
}
}
return true;
})
.withMessage("Invalid privileges")
.optional({ checkFalsy: true }),
],
async (req, res) => {
const errors = await validationResult(req);
console.log(errors);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
return res.status(200).json({ errors: "[]" });
}
);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});

Related

Node server keep shutting down when I start typing message

I am making a chat app, but when I write a message and press send, my node server keep giving me:
TypeError: Cannot read property 'trim' of undefined
or
TypeError: Cannot read property 'room' of undefined
Then it crashes, I don't know why, everything else was working normally, only the server crashes. I've tried fixing it myself to no avail, without the server, you can probably guess what will happen.
Here's the code:
index.js:
var express = require ('express')
var http = require ('http')
var { addUser, removeUser, getUser, getUsersInRoom } = require ('./user')
var router = require ('./router')
var { callbackify } = require('util')
var PORT = process.env.PORT || 5000
var app = express()
var server = http.createServer(app)
var io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
app.use(router)
io.on('connection', (socket) => {
socket.on('join', ({ name, room }, callback) =>{
var { error, user } = addUser({ id: socket.id, name, room })
if(error) return callback(error)
socket.emit('message', { user: 'admin', text: `Now, I- Oh, ${user.name}, welcome to room ${user.room},enjoy your time here!` })
socket.broadcast.to(user.room).emit('message',{user: 'admin', text:`Hey, just coming in to say ${user.name} joined, also, how you guys doin.`})
socket.join(user.room)
callback()
})
socket.on('sendMessage', (message, callback) => {
var user = getUser(socket.id)
io.to(user.room).emit('message', { user: user.name, text: message })
callback()
})
socket.on('disconnect', () => {
console.log('Aw they left :(');
});
});
server.listen(PORT, () => console.log (`This is Index, port ${PORT} secured, lots of unfixable bug`))
user.js(where the problem exist):
const users = []
const addUser = ({ id, name, room }) =>{
name = name.trim().toLowerCase()
room = room.trim().toLowerCase()
const existingUser = users.find((user) => user.room === room && user.name === name)
if(existingUser){
return {error: 'Username is already taken you dumbass'}
}
const user = {id, name, room}
users.push(user);
return{ user }
}
const removeUser = (id) =>{
const index = users.findIndex ((user) => user.id === id)
if(index !== -1) {
return users.splice(index, 1)[0]
}
}
const getUser = (id) => users.find((user) => user.id === id)
const getUsersInRoom = (room) => users.filter((user) => user.room === room)
module.exports = { addUser, removeUser, getUser, getUsersInRoom }
and router.js:
const express = require('express')
const router = express.Router();
router.get('/*', (req,res) =>{
res.send(`Server is up and running`)
})
module.exports = router;
That is all the server file because the problem comes from server, not client (there is not enough words in here so I have to do this)
Thanks in advance!
Both error is due to the application is trying to access a subfunction/subparameter of an undefined value.
Are you sure the client is sending the right param when emitting "join" ?
what you can do on the server side is do some validation and check if its undefined and set a default value if it is.
name = name ? name.trim().toLowerCase() : "default_name";
room = room ? room.trim().toLowerCase() : "default_room";
as for the Room of undefined error is most likely due to this part of the app
const existingUser = users.find((user) => user.room === room && user.name === name)
try checking if users.length, if it's 0 then don't bother doing .find(), or you can add validation inside the .find() function to check if user is undefined,then return false;
const existingUser = users.find((user) => user && user.room === room && user.name === name)
socket.on('join', ({ name, room }, callback) =>{
Where do you get name and room from?

Module's function is not being copied

I have defined a function in a module named server.js and want to use it in sign-in.js. server.js exports only one function-emailExists.
module.exports.emailExists = emailExists;
So I import it using:
const server = require("./../server");
and wish to use as
const emailExists = server.emailExists;// but emailExists is undefined
console.log("emailExists is ", typeof emailExists);// result undefined
but
the below is working as expected
console.log("server.emailExists is ", typeof server.emailExists); // returns function
I thought maybe functions are not copied or referenced, but the below code works as i want the above example to work
//this works as expected
function x() {
console.log("from x");
}
const y = x;
console.log("y is", typeof y); // logs y is function
y(); // returns "from x"
I am not sure whether the difference in these two examples is because in first case function is being copied/ referenced from another module and in the second case, function from the same file is bieng copied/ referenced, as few days ago i created new project just to check this and fuction from other module was being copied, i.e. the below was working.
const y= require("./mod2.js").x //x is function in mod2
console.log(typeof y)// returned fucntion
server.js
const express = require("express");
const path = require("path");
const multer = require("multer");
const db = require("./server/database/index.js");
const http = require("http");
const app = express();
const PORT = 3000;
const router = require("./routes/sign-in.js");
app.use(express.static("./"));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "./index.html"));
});
const upload = multer();
let OTP;
app.post("/sendOTP", upload.none(), async (req, res) => {
OTP = Math.ceil(Math.random() * 100000);
http
.get(
`http://myactualdomain.com:portthatiamusing/${OTP}/${req.body.email}`,
async (response) => {
console.log("got response from linux server");
let existingEmail = await emailExists(req.body.email);
if (existingEmail === true) {
res.json(existingEmail);
} else if (existingEmail === false) {
res.json(existingEmail);
} else {
res.json(await emailExists(req.body.email));
}
}
)
.on("error", (err) => {
res.json({ err });
});
});
async function emailExists(email) {
let sqlResponse = await db
.emailExists(email)
.then((data) => {
if (Object.keys(data).length === 0) {
return { exists: false };
} else {
return { exists: true };
}
})
.catch((err) => {
throw new Error("Error which checking if Email exists in MySQL");
});
return JSON.parse(sqlResponse.exists);
}
app.use(
"/",
(req, res, next) => {
req.OTP = OTP;
next();
},
router()
);
app.listen(PORT);
module.exports.emailExists = emailExists;
sign-in.js
const express = require("express");
const router = express.Router();
const multer = require("multer");
const upload = multer();
const db = require("../server/database/index.js");
const server = require("./../server");
const validateOTP = require("./validateOTP.js");
const emailExists = server.emailExists;
module.exports = () => {
router.use("/validateOTP", validateOTP());
router.post("/sign-in", upload.none(), async (req, res) => {
if (await server.emailExists(req.body.email)) {
let correctPassword = await db
.retreivePassword(req.body.email)
.then((password) => {
if (password[0].password === req.body.password) {
res.json({ successful: true });
} else {
res.json({ successful: false });
}
})
.catch((err) => {
res.json(err);
throw "Error checking password from MySql";
});
} else {
res.json({ successful: "email doesn't exist" });
}
//this works as expected
console.log("server.emailExists is ", typeof server.emailExists);
//this does not works as expected. expeted value function, actual value undefined
console.log("emailExists is ", typeof emailExists);
//this works as expected
function x() {
console.log("from x");
}
const y = x;
console.log("y is", typeof y); // logs y is function
y(); // returns "from x"
});
return router;
};

How to seperate websocket/express server into different files?

I am having trouble wrapping my head around the best way to execute some code below from a separate file. I have it running well in my my app.js but obviously, I do not want to keep a bunch of code in only app.js and want to start moving things into other files but am at a loss on how to do so. My app.js more or less looks like this and is extremely bloated:
//web server
const express = require('express');
const app = express();
const port = 3000;
//raspberryPI
const { ChatClient } = require("dank-twitch-irc");
const { yay } = require('./JavaScript/yay');
const { readPin } = require('./JavaScript/readPin');
let ejs = require('ejs');
//listen on port 3000
app.listen(port, () => console.info('Listening on port', { port }));
app.use(express.static('./'))
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index');
})
//Setup raspberry pi stepper motor hat
let spec = {
steppers: [{ W1: 'M1', W2: 'M2' }, { W1: 'M3', W2: 'M4'}],
//steppers: [{ W1: 'M3', W2: 'M4' }],
};
const motorHat = require('motor-hat')(spec);
motorHat.init();
motorHat.steppers[0].setSteps(2048);
motorHat.steppers[0].setSpeed({ rpm: 5 });
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
const keywordsList = [];
client.on("PRIVMSG", (msg, error) => {
console.log(`[#${msg.channelName}] ${msg.displayName}: ${msg.messageText}`);
const keywordFinder = /\b(^right)|(^left)|(^fire)\b/iy;
//empty array fixes null value
const keywords = msg.messageText.match(keywordFinder) || [];
if (msg.messageText === keywords[0]){
if (keywordsList.length>10){
keywordsList.shift();
}
keywordsList.push(`${msg.displayName}: ${msg.messageText}`);
console.log(keywordsList);
}
// keywordsList.forEach(keywords)
if (msg.messageText === "right") {
motorHat.steppers[0].stepSync('fwd', 12);
}
if (msg.messageText === "left") {
motorHat.steppers[0].stepSync('back', 12);
}
if (msg.messageText === "yay") {
yay();
}
if (msg.messageText === "pin") {
readPin();
}
if (error != null) {
console.error("Client closed due to error", error);
}
});
//connect to specific Twitch chat
client.connect();
client.join("yuhn");
and the code I am having trouble removing is this (sorry if redundant):
const keywordsList = [];
client.on("PRIVMSG", (msg, error) => {
console.log(`[#${msg.channelName}] ${msg.displayName}: ${msg.messageText}`);t
const keywordFinder = /\b(^right)|(^left)|(^fire)\b/iy;
//empty array fixes null value
const keywords = msg.messageText.match(keywordFinder) || [];
if (msg.messageText === keywords[0]){
if (keywordsList.length>10){
keywordsList.shift();
}
keywordsList.push(`${msg.displayName}: ${msg.messageText}`);
console.log(keywordsList);
}
// keywordsList.forEach(keywords)
if (msg.messageText === "right") {
motorHat.steppers[0].stepSync('fwd', 12);
}
if (msg.messageText === "left") {
motorHat.steppers[0].stepSync('back', 12);
}
if (msg.messageText === "yay") {
yay();
}
if (msg.messageText === "pin") {
readPin();
}
if (error != null) {
console.error("Client closed due to error", error);
}
});
What I thought I could do is just put the code in a separate file, make sure all my modules are connected (export client and import it into the separate files along with motorhat, etc) but it does not run. Any and all help is appreciated. I have attempted to read about this for a few hours now and I keep getting in depth guides to routing/express file structure...which is fine but I need to know if that's the direction to go in and if so, the first steps.
With my current understanding of your code, I would start by creating a file that contains the callback of your websocket event:
ws_callbacks.js
const motorHat = require('./main.js').motorHat
const keywordsList = [];
exports.PRIVMSG_callback = (msg, error) => {
console.log(`[#${msg.channelName}] ${msg.displayName}: ${msg.messageText}`);t
const keywordFinder = /\b(^right)|(^left)|(^fire)\b/iy;
//empty array fixes null value
const keywords = msg.messageText.match(keywordFinder) || [];
// Rest of your code
}
You can then access the callback by requiring ws_callbacks.js in your main file as so:
app.js
// ...
motorHat.init();
motorHat.steppers[0].setSteps(2048);
motorHat.steppers[0].setSpeed({ rpm: 5 });
exports.motorHat = motorHat
// ...
client.on("PRIVMSG", require('./ws_callbacks.js').PRIVMSG_callback )
// ...
Here, The callback accesses motorHat, which is why it is being exported within the app.js file.
Note that you can also export the other websocket callbacks (ready and close) in similar fashion.
If you prefer to keep all websocket-related code in a separate file, this is how I would write it:
chat.js
const { ChatClient } = require("dank-twitch-irc");
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
client.on("PRIVMSG", require('./ws_callbacks.js').PRIVMSG_callback )
// Exporting client in case you want to use it somewhere else
exports.client = client
And then import it in app.js.
However, you have mentioned experiencing problems with importing and exporting client so I am unsure if this will work

Why Math.js default takes multiply as operator when calculation an expression?

//Require module
const express = require('express');
const { evaluate, compile, parse } = require('mathjs');
// Express Initialize
const app = express();
const port = 8000;
app.listen(port, () => {
console.log('listen port 8000');
})
//create api
app.get('/hello_world', (req, res) => {
const expression = "A B A";
console.log(expression.length);
let response;
const scope = {
A: 5,
B: 4
}
try {
const parsedExp = parse(expression);
const compiled = parsedExp.compile();
const result = compiled.evaluate(scope);
response = {
"expression": parsedExp.toString(),
"variables": parsedExp.args,
"result": result
}
console.log("success");
res.send(JSON.stringify(response));
} catch (error) {
console.log(error);
res.send(JSON.stringify(error));
}
})
The code and calculation are working fine. but it's taking multiply by default. Is there a way we can stop this default behavior and throw an error message to the user that please enter your desired operator?
I tried even with normal javascript code by splitting with space and tried to check if of +,-,*,/,^ operator but the user can still give multiple spaces then writes another variable
Help appreciated
There is currently no option to disable implicit multiplication, but there is a (currently open) github issue for that. And in the comments of that issue there is a workaround to find any implicit multiplications and throw an error if one is found.
try {
const parsedExp = parse(expression);
parsedExp.traverse((node, path, parent) => {
if (node.type === 'OperatorNode' && node.op === '*' && node['implicit']) {
throw new Error('Invalid syntax: Implicit multiplication found');
}
});
...
} catch (error) {
console.log(error);
res.send(JSON.stringify(error));
}

Why does this mismatch in lexical scoping occur?

This issue occurs in both Node 6.9.4 and 7.0.0, and I cannot figure out why. I haven't tested in other versions. See comments in Node.js program below:
const express = require('express');
const adaro = require('adaro');
const app = express();
const tabs = require('./config/tabs.json');
const config = require('./config/locals.js');
function getLocals(name) {
const modifiedTabs = config.tabs.map(tab => {
return Object.assign(tab, {active: tab.name === name});
});
return Object.assign({tab: name}, config, {tabs: modifiedTabs});
}
app.engine('dust', adaro.dust());
app.set('view engine', 'dust');
app.set('x-powered-by', false);
app.use(express.static('static'));
tabs.map(tab => tab.name).forEach(name => {
const locals = getLocals(name);
const tab = locals.tabs.find(tab => tab.active);
// these are always true
console.log(tab === locals.tabs.find(tab => tab.active));
function callback(req, res) {
// const locals = getLocals(name);
// this should be true, but is false unless the line above is commented in
console.log(tab === locals.tabs.find(tab => tab.active));
res.render('main', locals);
}
if (tab.url !== '/' + tab.id) {
app.get(tab.url, callback);
}
app.get('/' + tab.id, callback);
});
app.all('*', function (req, res) {
res.sendStatus(404);
});
app.listen(process.env.PORT || 8000);
Can anyone explain why this is happening and how to fix it?
I found the issue. In getLocals(), I'm executing
const modifiedTabs = config.tabs.map(tab => {
return Object.assign(tab, {active: tab.name === name});
});
The Object.assign(tab, ...) overwrites the existing tab object each time it's called, leaving only the last assignments to each tab. So all the views show the last tab in the array as active, since all their active properties have been overwritten with those of the last tab's configuration.
The solution was to switch the arguments to Object.assign() so that the returned object was created rather than overwritten:
return Object.assign({active: tab.name === name}, tab);

Categories