How to create login endpoint using express-session and express-mysql-session - mysql

I want to create a secure login. I'd like to add session but I can't figure out how they should be used together.
I have 2 codes, one code came from express-mysql-session and another code which I wrote and has the login (/api/login) endpoint.
Below is the code which I copied from the readme.md of express-mysql-session and it works.
var express = require('express');
var app = module.exports = express();
var session = require('express-session');
var MySQLStore = require('express-mysql-session')(session);
var options = {
host: 'localhost',
port: 3306,
user: 'root',
password: 'password',
database: 'session_test'
};
var sessionStore = new MySQLStore(options);
app.use(session({
key: 'session_cookie_name',
secret: 'session_cookie_secret',
store: sessionStore,
resave: true,
saveUninitialized: true
}));
Here is the output on the terminal. The code above ran well but not really sure what it did. I see it has established connection to the locally running mysql using netstat command
tcp4 0 0 127.0.0.1.3306 127.0.0.1.52470 ESTABLISHED
tcp4 0 0 127.0.0.1.52470 127.0.0.1.3306 ESTABLISHED
then the output
$ DEBUG=express-mysql-session* node index.js
express-mysql-session:log Creating session store +0ms
express-mysql-session:log Setting default options +2ms
express-mysql-session:log Creating sessions database table +46ms
express-mysql-session:log Setting expiration interval: 900000ms +42ms
express-mysql-session:log Clearing expiration interval +0ms
Then below is the basic login auth endpoint I created using Express. This works but I want to add express-session, express-mysql-session as well as use crypt, bcrypt or scrypt-for-humans but not sure how to integrate it.
const express = require('express');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const app = express();
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.set('port', (process.env.API_PORT || 8000));
const connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'authdb'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
app.post('/api/login', function(req, res) {
const user_id = req.body.user_id;
const password = req.body.password;
let response = {};
res.setHeader('Content-Type', 'application/json');
connection.query('SELECT password from user WHERE `username` = "' + user_id + '"' , function(err, rows) {
if (err) throw err;
if (rows.length > 0) {
if (password === rows[0].password) {
response.status = 200;
response.message = "authenticated";
response.authenticated = true;
response.user_id = user_id;
} else {
response.status = 403;
response.message = "Login failed!";
response.authenticated = false;
response.user_id = user_id;
}
} else {
response.status = 403;
response.message = "Login failed!";
response.authenticated = false;
response.user_id = user_id;
}
res.status(response.status).send(JSON.stringify(response));
});
});
app.listen(app.get('port'), () => {
console.log(`Find the server at: http://localhost:${app.get('port')}/`);
});

I got it working and quite happy with the results. My login endpoint is working great! I now have more ideas on how to make it better as well. Here is the screenshot of the REST client - http://i.imgur.com/fJOvmzh.png and below is the endpoint
app.post('/api/login', function(req, res) {
const user_id = req.body.user_id;
const password = req.body.password;
let response = {};
res.setHeader('Content-Type', 'application/json');
connection.query('SELECT * FROM authdb.users as authusers inner join authdb.passwords as hashed on authusers.email = hashed.email WHERE authusers.email = "' + user_id + '"' , function(err, rows) {
if (err) throw err;
Promise.try(function(){
return scrypt.verifyHash(password, rows[0].password);
}).then(function(){
var sess = req.session;
if (sess.views) {
sess.views++;
} else {
sess.views = 1
}
response = { status: 200, message: "Login successful!", authenticated: true, user_id: user_id, views: sess.views }
res.status(response.status).send(JSON.stringify(response));
}).catch(scrypt.PasswordError, function(err){
response = { status: 403, message: "Login failed!", authenticated: false, user_id: user_id }
res.status(response.status).send(JSON.stringify(response));
});
});
});
To make it secure, I'll setup an EC2 behind an ELB which terminates all SSL connections and sends all traffic in clear to the NodeJS running my Express auth API spawned by PM2 or other better balancers. The AWS secgroup will only accept traffic whose source is the ELB.

Related

Getting "Cannot GET /isFavorite" on my Node.js app hosted on DigitalOcean

Why am I getting the following error? I have a small Nodejs app hosted on DigitalOcean. I am getting the following error "Cannot GET /isFavorite" when I run the following post command in Postman: "http://octopus-app-s7q5v.ondigitalocean.app:8080/isFavorite" with body JSON parameters of:
{
"userid": "101",
"petid": "1"
}
The route I have for the app is an app.post("/isFavorite") and not an app.get. It is connected to a MySQL database which is also hosted on DigitalOcean. I have included a small version of the code for the app below. Why would I be getting this error? When I add an app.get("/") and return a response of "Hello" that works. It runs locally. I have configured all the environment variables in DigitalOcean settings. I have the "ca-certificate.crt" in the root of my Nodejs app. DigitalOcean app platform says it builds and deploys fine on the server.
Also, regarding the console.logs I have added to the code, where are they stored? I can see the one which starts the webserver and listens but not any of the others. The app is listening on port 8080 and has an IP address of 0.0.0.0.
const bodyParser = require("body-parser");
const querystring = require('querystring');
const router = express.Router();
const app = express();
app.use("/", router);
const mysql = require('mysql');
const fs = require('fs');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.json());
app.post("/isFavorite", (req, res) => {
try {
console.debug("isFavorite Start");
const conn = mysql.createConnection({
host: process.env.DBHOST,
port: process.env.DBPORT,
user: process.env.DBUSER,
database: process.env.DBNAME,
password: process.env.DBPASSWORD
});
console.log("isFavorite logged on to db");
let selectQuery = 'SELECT COUNT(*) c FROM Favorites WHERE userID = ? AND petID = ?';
let query = mysql.format(selectQuery,[req.body.userid, req.body.petid]);
conn.query(query,(err, response, fields) => {
if(err) {
console.log(err);
res.status(500).send("Error querying database.");
return;
}
// rows added
console.log("isFavorite");
console.log(response.length);
if (response.length > 0) {
console.log(JSON.stringify(response));
res.status(200).json({IsFavorite: response[0].c >= 1});
} else {
res.status(200).json({IsFavorite: false});
}
});
} catch (err) {
next(err);
}
});
let PORT = process.env.PORT || 3000;
let IP = process.env.IP || '127.0.0.1';
app.listen(PORT, IP, () => {
console.log('Server is running at port ' + PORT + ' and IP = ' + IP);
});

Error in delete DB record using Node.JS and MYSQL

I'm performing CRUD operations using MYSQL and NodeJS express. Their error in deleting a record from DB, I don't know why I was getting a problem as i have copied the delete query from SQL where it is working properly. Here it is 'DELETE FROM tblltest WHERE id=?'. I manually add 'id' like 'DELETE FROM tblltest WHERE id=2' then it will delete the record from DB. Please help me out to solve this issue. Here are my lines of code.
var express = require('express');
var mysql = require('mysql');
var app = express();
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'sampledb'
});
app.delete('/:id' , function(req , resp) {
connection.query('DELETE FROM `tblltest` WHERE `id`=?' , function(error , rows , fields){
if(!error){
console.log('Successful deleted!! \n');
resp.json(rows);
}else{
console.log('Error in deleting');
}
});
})
app.listen(1337);
You need to access the id route parameter in your delete API Node method, and then also bind this id value to the delete query:
app.delete('/:id', function(req, resp) {
var id = req.params.id;
connection.query('DELETE FROM tblltest WHERE id = ?', [id],
function(error, rows, fields) {
if (!error) {
console.log('Successful deleted!! \n');
resp.json(rows);
}
else {
console.log('Error in deleting');
}
});
})
var express = require('express');
var app = express();
var mysql = require('mysql');
var bodyParser = require('body-parser');
//start mysql connection
var connection = mysql.createConnection({
host : 'localhost', //mysql database host name
user : 'root', //mysql database user name
password : '', //mysql database password
database : 'sampledb' //mysql database name
});
connection.connect(function(err) {
if (err) throw err
console.log('You are now connected...')
})
//end mysql connection
//start body-parser configuration
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
//end body-parser configuration
//create app server
var server = app.listen(1337, "127.0.0.1", function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
//rest api to delete record from mysql database
app.delete('/employees', function (req, res) {
console.log(req.body);
connection.query('DELETE FROM `tblltest` WHERE `id`=?', [req.body.id], function (error, results, fields) {
if (error) throw error;
res.end('Record has been deleted!');
});
});

Extracting information from reddit json and placing it in mysql database using node.js

I'm trying to extract JSON data from /r/askreddit and put it in a mysql database table called "post". The columns in the table are information such as the title of the post, url of the post, and the username of the poster.
I'm at a complete loss at this point on how to bring the data from the raw JSON into my table from the raw JSON, as I thought it should now be working.
Here is my .js server file, any help is appreciated. Thanks.
/*jshint esversion: 6 */
let mysql = require('mysql2');
let dbInfo = require('./dbInfo.js');
let express = require('express');
let bodyParser = require("body-parser");
let app = express();
// Add static route for non-Node.js pages
app.use(express.static('public'));
// Configure body parser for handling post operations
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/reddit-import', function (req, res) {
console.log("Route for the /r/askreddit POST");
let sql = for (let i=0; i < x.data.children.length; i++) {
"insert into post (post_title, post_date, post_url, user_name) values (?,?,?,?)"
};
let data = [req.body.post_title, req.body.post_date, req.body.post_url, req.body.user_name];
connection.query(sql,
data,
function (errQuery, result) {
if (errQuery) {
console.log(errQuery);
res.json({status: "Error", err: errQuery});
} else {
console.log("Insert ID: ", result.insertId);
res.json({status: result.insertId, err: ""});
}
}
);
});
// Create database connection
console.log('Creating connection...\n');
let connection = mysql.createConnection({
host: dbInfo.dbHost,
port: dbInfo.dbPort,
user: dbInfo.dbUser,
password: dbInfo.dbPassword,
database: dbInfo.dbDatabase
});
// Connect to database
connection.connect(function(err) {
console.log('Connecting to database...\n');
// Handle any errors
if (err) {
console.log(err);
console.log('Exiting application...\n');
} else {
console.log('Connected to database...\n');
// Listen for connections
// Note: Will terminate with an error if database connection
// is closed
const ip = 'localhost';
const port = 8080;
app.listen(port, ip, function () {
try {
console.log('Alumni server app listening on port ' + port);
} catch (err) {
console.log(err);
}
});
}
});

Persistent Session in Nodejs using MySql

new to nodejs. this might be a silly/easy question
I have an Express App and i am using mysql for persistent sessions. (using express-mysql-session to do that).
Here's code snippet from app.js:
var express = require('express');
var session = require('express-session');
var SessionStore = require('express-mysql-session');
var app = express();
app.use(session({
store: new SessionStore({
host: 'localhost',
user: 'test',
password: 'test',
database: 'test'
}),
secret: 'secret_key',
resave: false,
saveUninitialized: false
}));
routes.js
module.exports = function(app) {
app.post('/login', wrap(function* (req, res) {
var email = req.body.email;
var password = req.body.password;
var response = yield new AccountController().login(email, password);
if (response.status === 'success') {
req.session.account = {
accountId: response.accountId,
accountStatus: response.accountStatus
};
req.session.save(function(err) {
if (err) console.log('error in saving session: ' + err);
});
}
}
}));
The get and set method of express-mysql-session are called everytime a request is sent.
I wanted to know how can i set my custom data into the persistent session store without using any other library like passport.
and also how to read the store too.

How to provide a mysql database connection in single file in nodejs

I need to provide the mysql connection for modules. I have a code like this.
var express = require('express'),
app = express(),
server = require('http').createServer(app);
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'chat'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
});
app.get('/save', function(req,res){
var post = {from:'me', to:'you', msg:'hi'};
var query = connection.query('INSERT INTO messages SET ?', post, function(err, result) {
if (err) throw err;
});
});
server.listen(3000);
But how we provide one time mysql connection for all the modules.
You could create a db wrapper then require it. node's require returns the same instance of a module every time, so you can perform your connection and return a handler. From the Node.js docs:
every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
You could create db.js:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'chat'
});
connection.connect(function(err) {
if (err) throw err;
});
module.exports = connection;
Then in your app.js, you would simply require it.
var express = require('express');
var app = express();
var db = require('./db');
app.get('/save',function(req,res){
var post = {from:'me', to:'you', msg:'hi'};
db.query('INSERT INTO messages SET ?', post, function(err, result) {
if (err) throw err;
});
});
server.listen(3000);
This approach allows you to abstract any connection details, wrap anything else you want to expose and require db throughout your application while maintaining one connection to your db thanks to how node require works :)
I took a similar approach as Sean3z but instead I have the connection closed everytime i make a query.
His way works if it's only executed on the entry point of your app, but let's say you have controllers that you want to do a var db = require('./db'). You can't because otherwise everytime you access that controller you will be creating a new connection.
To avoid that, i think it's safer, in my opinion, to open and close the connection everytime.
here is a snippet of my code.
mysq_query.js
// Dependencies
var mysql = require('mysql'),
config = require("../config");
/*
* #sqlConnection
* Creates the connection, makes the query and close it to avoid concurrency conflicts.
*/
var sqlConnection = function sqlConnection(sql, values, next) {
// It means that the values hasnt been passed
if (arguments.length === 2) {
next = values;
values = null;
}
var connection = mysql.createConnection(config.db);
connection.connect(function(err) {
if (err !== null) {
console.log("[MYSQL] Error connecting to mysql:" + err+'\n');
}
});
connection.query(sql, values, function(err) {
connection.end(); // close the connection
if (err) {
throw err;
}
// Execute the callback
next.apply(this, arguments);
});
}
module.exports = sqlConnection;
Than you can use it anywhere just doing like
var mysql_query = require('path/to/your/mysql_query');
mysql_query('SELECT * from your_table where ?', {id: '1'}, function(err, rows) {
console.log(rows);
});
UPDATED:
config.json looks like
{
"db": {
"user" : "USERNAME",
"password" : "PASSWORD",
"database" : "DATABASE_NAME",
"socketPath": "/tmp/mysql.sock"
}
}
Hope this helps.
I think that you should use a connection pool instead of share a single connection. A connection pool would provide a much better performance, as you can check here.
As stated in the library documentation, it occurs because the MySQL protocol is sequential (this means that you need multiple connections to execute queries in parallel).
Connection Pool Docs
From the node.js documentation, "To have a module execute code multiple times, export a function, and call that function", you could use node.js module.export and have a single file to manage the db connections.You can find more at Node.js documentation. Let's say db.js file be like:
const mysql = require('mysql');
var connection;
module.exports = {
dbConnection: function () {
connection = mysql.createConnection({
host: "127.0.0.1",
user: "Your_user",
password: "Your_password",
database: 'Your_bd'
});
connection.connect();
return connection;
}
};
Then, the file where you are going to use the connection could be like useDb.js:
const dbConnection = require('./db');
var connection;
function callDb() {
try {
connection = dbConnectionManager.dbConnection();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (!error) {
let response = "The solution is: " + results[0].solution;
console.log(response);
} else {
console.log(error);
}
});
connection.end();
} catch (err) {
console.log(err);
}
}
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'yourip',
port : 'yourport',
user : 'dbusername',
password : 'dbpwd',
database : 'database schema name',
dateStrings: true,
multipleStatements: true
});
// TODO - if any pool issues need to try this link for connection management
// https://stackoverflow.com/questions/18496540/node-js-mysql-connection-pooling
module.exports = function(qry, qrytype, msg, callback) {
if(qrytype != 'S') {
console.log(qry);
}
pool.getConnection(function(err, connection) {
if(err) {
if(connection)
connection.release();
throw err;
}
// Use the connection
connection.query(qry, function (err, results, fields) {
connection.release();
if(err) {
callback('E#connection.query-Error occurred.#'+ err.sqlMessage);
return;
}
if(qrytype==='S') {
//for Select statement
// setTimeout(function() {
callback(results);
// }, 500);
} else if(qrytype==='N'){
let resarr = results[results.length-1];
let newid= '';
if(resarr.length)
newid = resarr[0]['#eid'];
callback(msg + newid);
} else if(qrytype==='U'){
//let ret = 'I#' + entity + ' updated#Updated rows count: ' + results[1].changedRows;
callback(msg);
} else if(qrytype==='D'){
//let resarr = results[1].affectedRows;
callback(msg);
}
});
connection.on('error', function (err) {
connection.release();
callback('E#connection.on-Error occurred.#'+ err.sqlMessage);
return;
});
});
}
try this
var express = require('express');
var mysql = require('mysql');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
console.log(app);
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "admin123",
database: "sitepoint"
});
con.connect(function(err){
if(err){
console.log('Error connecting to Db');
return;
}
console.log('Connection established');
});
module.exports = app;
you can create a global variable and then access that variable in other files.
here is my code, I have created a separate file for MySQL database connection called db.js
const mysql = require('mysql');
var conn = mysql.createConnection({
host: "localhost",
user: "root",
password: "xxxxx",
database: "test"
});
conn.connect((err) => {
if (err) throw err;
console.log('Connected to the MySql DB');
});
module.exports = conn;
Then in the app.js file
const express = require('express');
const router = express.Router();
// MySql Db connection and set in globally
global.db = require('../config/db');
Now you can use it in any other file
const express = require('express');
const router = express.Router();
router.post('/signin', (req, res) => {
try {
var param = req.body;
var sql = `select * from user`;
// db is global variable
db.query(sql, (err, data) => {
if (err) throw new SyntaxError(err);
res.status(200).json({ 'auth': true, 'data': data });
});
} catch (err) {
res.status(400).json({ 'auth': false, 'data': err.message });
}
});