-
-
Save obazoud/5618185 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var config = { | |
"database": { | |
"connection": "mongodb://localhost/scrapService" | |
}, | |
"cookieSecret": "EhAIj3NmtJ1sem5StHXV0Mk" | |
}; | |
require("./user") | |
var express = require('express') | |
, mongoose = require('mongoose') | |
, User = mongoose.models["User"] | |
, loginApp = require('./login') | |
, _ = require("underscore"); | |
var app = express(); | |
mongoose.connect(config.database.connection); | |
app.set("json spaces", true); | |
app.set("json replacer", function (key, value) { | |
if (value && value._id) { | |
value.id = value._id; | |
value._id = undefined; | |
} | |
if (key == "__v" || key == "updatedAt" || key == "createdAt" || key == "_id") return undefined; | |
return value; | |
}) | |
app.configure(function () { | |
app.set('views', __dirname + '/views'); | |
app.set('view engine', 'jade'); | |
app.use(express.bodyParser()); | |
app.use(express.cookieParser(config.cookieSecret)); | |
app.use(express.session()); | |
app.use(express.methodOverride()); | |
app.use('/rest/user', loginApp()); | |
app.use(app.router); | |
app.use(express.static(__dirname + '/public')); | |
} | |
app.get("/rest/something/to/authenticate",loginApp.authenticate,function(req,res,next){}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require("express") | |
, mongoose = require("mongoose") | |
, _ = require('underscore') | |
, security = require('./security')() | |
var User; | |
function register(req,res,next) { | |
var options = req.body; | |
if (!req.body.userInfo) return res.send(400, "UserInfo is required"); | |
var entity = User.buildSecure(req.body.userInfo); | |
delete options.userInfo; | |
User.findOne({ "email": entity.email }, function (err, dbEntity) { | |
if (err) { | |
next(err); | |
} | |
if (dbEntity === null || dbEntity == undefined || dbEntity.length == 0) { | |
savedEntity.password = undefined; | |
login(req,res,savedEntity); | |
} else { | |
res.send(409, "Entity already exists"); | |
} | |
}); | |
} | |
function loginByUserPass(req, res, email, password,onSuccess) { | |
User.findByPassword(email, password, function (user) { | |
if (_.isString(user)) { | |
res.send(403, user); | |
} else { | |
if (req.body.rememberMe) { | |
var token = security.getRandomSalt() | |
, expires = new Date(Date.now() + 900000); | |
res.cookie("rmToken", { id: user._id, | |
token: token | |
} | |
, { | |
expires: expires, | |
httpOnly: true, | |
signed: true | |
}); | |
User.findByIdAndUpdate(user, { $addToSet: { tokens: { token: token, expires: expires}} }, | |
function (err, dbUser) { | |
if (err) throw err; | |
login(req, res, dbUser); | |
}); | |
} else { | |
login(req, res, user); | |
} | |
} | |
}); | |
} | |
function login(req,res,user) { | |
req.session.user = user; | |
res.json({ success: true, | |
userInfo: user, | |
rememberMe: req.body.rememberMe ? true : false | |
}); | |
} | |
function loginByToken(req, res, userId, token,onSuccess) { | |
User.findById(userId).exec(function (err, user) { | |
if (!user) { | |
res.send(403, "user unknown"); | |
} else { | |
var dbToken = _.find(user.tokens, function (item) { return item.token == token }); | |
if (dbToken) { | |
dbToken.token = security.getRandomSalt(); | |
dbToken.expires = new Date(Date.now() + 90000000) | |
res.cookie("rmToken", { id: user._id, | |
token: dbToken.token | |
} | |
, { | |
expires: dbToken.expires, | |
httpOnly: true, | |
signed: true | |
}); | |
User.update({ _id: user._id, 'tokens._id': dbToken._id }, { $set: { 'tokens.$.token': dbToken.token, 'tokens.$.expires': dbToken.expires} }, function (err, dbUser) { | |
if (err) throw err; | |
req.body.rememberMe = true; | |
login(req, res, dbUser) | |
}); | |
} else { | |
res.send(403, "bad token"); | |
} | |
} | |
}) | |
} | |
function logout(req,res) { | |
var async = false; | |
if (req.signedCookies.rmToken) { | |
var user = req.user; | |
var tokenUser = req.signedCookies.rmToken.id; | |
var token = req.signedCookies.rmToken.token; | |
if (user._id ==tokenUser) { | |
for (var i=0;i< user.tokens.length;i++) { | |
if (user.tokens[i].token == token) { | |
async = true; | |
User.findByIdAndUpdate(user._id, { $pull: { tokens: { _id: user.tokens[i]._id}} }, function (err, dbUser) { | |
if (err) throw err; | |
res.send(200, { result: "logged out" }); | |
}) | |
break; | |
} | |
} | |
} | |
res.clearCookie("rmToken"); | |
} | |
if (req.session) req.session.destroy(); | |
if (!async) res.send(200,{result:"logged out"}); | |
} | |
module.exports = function () { | |
var app = express(); | |
User = mongoose.models["User"], | |
app.post("/login", function (req, res, next) { | |
if (req.body.password) { | |
loginByUserPass(req, res, req.body.email, req.body.password); | |
} else if (req.signedCookies.rmToken) { | |
loginByToken(req, res, req.signedCookies.rmToken.id, req.signedCookies.rmToken.token); | |
} else { | |
res.send(400, "malformed url"); | |
} | |
}) | |
app.post("/logout", module.exports.authenticate, logout); | |
app.post("/", register); | |
return app; | |
} | |
module.exports.authenticate = function (req, res, next) { | |
if (!req.session || !req.session.user) return res.send(403, "not logged in"); | |
req.user = req.session.user; | |
next(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var crypto = require('crypto'); | |
var _ = require('underscore'); | |
module.exports = function (options) { | |
var defaultOptions = { | |
saltSize: 20, | |
saltLength: 64, | |
secretKey: "", | |
algorithm: "sha512" | |
} | |
options = _.extend(defaultOptions, options); | |
var saltpool = []; | |
var last_salt = Math.random().toString('36').replace('0.', '') | |
+ Math.random().toString('36').replace('0.', '') | |
+ Math.random().toString('36').replace('0.', ''); | |
function addSaltToPool() { | |
if (saltpool.length <= options.saltSize) { | |
crypto.randomBytes(options.saltLength, function (ex, buf) { | |
var result = buf.toString('base64').replace(/\//g, '_').replace(/\+/g, '-'); | |
saltpool.push(result); | |
last_salt = result; | |
addSaltToPool(); | |
}); | |
} | |
} | |
addSaltToPool(); | |
var m = {}; | |
m.hash = function hash(raw) { | |
'use strict'; | |
var h = crypto.createHash(options.algorithm); | |
h.update(raw); | |
return h.digest("base64"); | |
}; | |
m.getRandomSalt = | |
function getRandomSalt() { | |
var result = saltpool.pop(); | |
if (result === undefined || result === null) { | |
result = last_salt; | |
} | |
addSaltToPool(); | |
return result; | |
} | |
m.hashPassword = function (password, salt) { | |
if (salt === undefined || salt === null) salt = m.getRandomSalt(); | |
var hashed = m.hash(salt + password + options.secretKey); | |
return salt + "::" + hashed; | |
} | |
m.samePassword = function (toCompare, goodPassword) { | |
if (!goodPassword) throw new Error("hashedValue has bad format: " + goodPassword); | |
var parts = goodPassword.split("::"); | |
if (parts === undefined || parts === null || parts.length != 2) { | |
throw new Error("hashedValue has bad format: " + goodPassword); | |
} | |
return goodPassword == m.hashPassword(toCompare, parts[0]); | |
} | |
return m; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mongoose = require('mongoose') | |
var security = require('./security')(); | |
var Schema = mongoose.Schema; | |
var schema = new Schema({ | |
email: { type: String, unique: true }, | |
password: {type: String, select: false}, | |
firstName: String, | |
lastName: String, | |
tokens: { type: Array, cast: { | |
token: String, | |
expires: Date | |
} | |
} | |
}); | |
schema.statics.buildSecure = function (raw) { | |
delete raw.tokens; | |
delete raw.accounts; | |
var entity = new this(raw) | |
entity.password = security.hashPassword(entity.password); | |
return entity; | |
}; | |
schema.statics.findByPassword = function (email, password, callback) { | |
var result = this.findOne({ email: email }).select("+password").exec(function (err, result) { | |
if (result === undefined || result === null || result.length == 0) { | |
result = "User does not exists"; | |
} else if (!security.samePassword(password, result.password)) { | |
result = "Bad password"; | |
} else { | |
result.password = undefined; | |
result = result; | |
} | |
callback(result); | |
}) | |
} | |
var User = mongoose.model('User', schema); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment