diff --git a/mobility-track-nodejs/controllers/tracker.js b/mobility-track-nodejs/controllers/tracker.js index b4577aa..220ad00 100644 --- a/mobility-track-nodejs/controllers/tracker.js +++ b/mobility-track-nodejs/controllers/tracker.js @@ -3,10 +3,16 @@ * GET users listing. */ +var jwt = require('jsonwebtoken'); + var mongoose = require('mongoose') , TrackerLocations = mongoose.model('TrackerLocations') , Tracker = mongoose.model('Tracker') +var User = require('../models/User'); + + + exports.locations = function (req, res) { TrackerLocations.aggregate( @@ -210,3 +216,140 @@ exports.listLocationsById = function(req, res){ }); } +exports.authenticate = function (req, res) { + var username = req.body.username; + var password = req.body.password; + if (username) { + if (password) { + User.findOne({ + 'userDetails.username': username + }, function (err, user) { + if (err) throw err; + if (!user) { + res.json({ + success: false, + message: 'Authentication failed. User not found:' + username + }); + } else if (user) { + var hash = user.generateHash(password); + if (!user.validPassword(password)) { // check if password matches + res.json({ + success: false, + message: 'Authentication failed. Wrong password.' + }); + } else { + sendToken(req, res, user); + } + } + }); + }else { + res.status(400).json({ + success: false, + message: 'Authentication failed. Password required.' + }); + } + } else { + res.status(400).json({ + success: false, + message: 'Authentication failed. Username required.' + }); + } +}; + +var sendToken = function (req, res, user) { + var apiSecret = 'temporarySecret'; + var tempUser = { + app: 'tracker', + context: { + username: user.userDetails.username, + } + }; + + var token = jwt.sign(tempUser, apiSecret, { + expiresInMinutes: 1440 // expires in 24 hours + }); + + return res.json({ + success: true, + token: token + }); +}; + +exports.signup = function (req, res) { + var username = req.body.username; + var password = req.body.password; + var name = req.body.name; + + if (username) { + if (password) { + User.findOne({ + 'userDetails.username': username + }, function (err, user) { + if (err) { + return res.json({ + success: false, + message: 'Unexpected Error while checking user' + }); + } else { + if (user) { + return res.json({ + success: false, + message: 'Error: User already exists' + }); + } else { + + var newUser = new User(); + + newUser.userDetails.username = username; + newUser.userDetails.name = name; + newUser.userDetails.password = newUser.generateHash(password); + + newUser.save(function (err) { + if (err) { + return res.json({ + success: false, + message: 'Unexpected Error while saving new user' + }); + } + else{ + return res.status(200).json({ + success: true, + message: 'User created' + }); + } + }); + } + } + }); + } else { + res.status(400).json({ + success: false, + message: 'Authentication failed. Password required.' + }); + } + } else { + res.status(400).json({ + success: false, + message: 'Authentication failed. Username required.' + }); + } +} + + + + + + + + + + + + + + + + + + + diff --git a/mobility-track-nodejs/models/User.js b/mobility-track-nodejs/models/User.js new file mode 100644 index 0000000..c4109af --- /dev/null +++ b/mobility-track-nodejs/models/User.js @@ -0,0 +1,28 @@ +// get an instance of mongoose and mongoose.Schema +var mongoose = require('mongoose'); +var bcrypt = require('bcrypt-nodejs'); + +var userSchema = mongoose.Schema({ + userDetails: { + name: String, + username: String, + password: String, + created: { + type: Date, + default: Date.now + } + } +}); + +// generating a hash +userSchema.methods.generateHash = function (password) { + return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); +}; + +// checking if password is valid +userSchema.methods.validPassword = function (password) { + return bcrypt.compareSync(password, this.userDetails.password); +}; + +// create the model for users and expose it +module.exports = mongoose.model('User', userSchema); \ No newline at end of file diff --git a/mobility-track-nodejs/package.json b/mobility-track-nodejs/package.json index c8fe749..ce11643 100644 --- a/mobility-track-nodejs/package.json +++ b/mobility-track-nodejs/package.json @@ -16,9 +16,14 @@ "express" ], "dependencies": { + "bcrypt-nodejs": "latest", + "jsonwebtoken": "^5.5.4", "express": "~3.1.0", "mongoose": "~3.8.8", "ejs": "^2.3.1", + "passport": "^0.3.2", + "passport-local": "^1.0.0", + "connect-flash": "^0.1.1", "ejs-locals": "^1.0.2" }, "devDependencies": { diff --git a/mobility-track-nodejs/passport.js b/mobility-track-nodejs/passport.js new file mode 100644 index 0000000..b6f29e9 --- /dev/null +++ b/mobility-track-nodejs/passport.js @@ -0,0 +1,57 @@ +var LocalStrategy = require('passport-local').Strategy; + +var User = require('./models/User'); + +module.exports = function (passport) { + + // used to serialize the user for the session + passport.serializeUser(function (user, done) { + done(null, user._id); + }); + + // used to deserialize the user + passport.deserializeUser(function (id, done) { + User.findOne({ + _id: id + }).exec(function (error, user) { + if (error) { + done(error); + } else { + if (user) { + done(null, user); + } else { + done(null, false); + } + } + }); + }); + + // ========================================================================= + // LOCAL LOGIN ============================================================= + // ========================================================================= + passport.use('local-login', new LocalStrategy({ + /* by default, local strategy uses username and password, we will override with email*/ + usernameField: 'username', + passwordField: 'password', + passReqToCallback: true // allows us to pass in the req from our route (lets us check if a user is logged in or not) + }, + function (req, username, password, done) { + var tempUser; + process.nextTick(function () { + User.findOne({'userDetails.username': username}, function (err, user) { + if (err) { + return done(err); + } + if (!user) { + return done(null, false, req.flash('loginMessage', 'No user found.')); + } + if (!user.validPassword(password)) { + return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); + } + else { + return done(null, user); + } + }); + }); + })); +}; diff --git a/mobility-track-nodejs/routes.js b/mobility-track-nodejs/routes.js index 43fbac4..90b7da4 100644 --- a/mobility-track-nodejs/routes.js +++ b/mobility-track-nodejs/routes.js @@ -1,4 +1,4 @@ -module.exports = function(app){ +module.exports = function(app, passport){ var controllers = require('./controllers/index'); var tracker = require('./controllers/tracker'); var resources = require('./controllers/resources'); @@ -20,6 +20,15 @@ app.get('/api/tracker/:id/delete', tracker.delete); app.get('/api/tracker/findmac/:mac', tracker.findMac); app.get('/api/trackers', tracker.getTrackers); +//authentication +app.post('/signup',tracker.signup); +app.post('/authenticate', tracker.authenticate); +app.post('/login',passport.authenticate('local-login', { + successRedirect: '/home', // redirect to the secure profile section + failureRedirect: '/login', // redirect back to the login page if there is an error + failureFlash: true // allow flash messages +})); + //TrackerLocation app.get('/api/tracker/location/data', tracker.listLocationData); app.post('/api/tracker/location/data', tracker.addLocationData); @@ -29,4 +38,3 @@ app.get('/api/tracker/:id/location/data', tracker.listLocationsById); app.post('/api/resources/create', resources.create); }; - diff --git a/mobility-track-nodejs/server.js b/mobility-track-nodejs/server.js index 2b8d1dd..3705f7e 100644 --- a/mobility-track-nodejs/server.js +++ b/mobility-track-nodejs/server.js @@ -19,6 +19,10 @@ var express = require('express'), var app = express(); +var passport = require('passport'); +var flash = require('connect-flash'); + +require('./passport')(passport); app.configure(function(){ app.set('port', process.env.PORT || 3000); @@ -33,8 +37,15 @@ app.configure(function(){ }); app.use(express.favicon()); app.use(express.logger('dev')); + app.use(express.cookieParser()); app.use(express.bodyParser()); + app.use(express.session({ secret: 'temporarySecret' })); app.use(express.methodOverride()); + + app.use(passport.initialize()); + app.use(passport.session()); + app.use(flash()); + app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); }); @@ -49,8 +60,10 @@ app.configure('development', function(){ app.use(express.errorHandler()); }); + + //Routes -require('./routes')(app); +require('./routes')(app,passport); //===============================