diff options
Diffstat (limited to '')
-rw-r--r-- | lib/auth.js | 27 | ||||
-rw-r--r-- | lib/config.js | 2 | ||||
-rw-r--r-- | lib/migrations/20161201050312-support-email-signin.js | 13 | ||||
-rw-r--r-- | lib/models/user.js | 33 | ||||
-rw-r--r-- | lib/realtime.js | 10 | ||||
-rwxr-xr-x | lib/response.js | 16 |
6 files changed, 87 insertions, 14 deletions
diff --git a/lib/auth.js b/lib/auth.js index 76a962f5..f167cede 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -7,6 +7,8 @@ var GithubStrategy = require('passport-github').Strategy; var GitlabStrategy = require('passport-gitlab2').Strategy; var DropboxStrategy = require('passport-dropbox-oauth2').Strategy; var GoogleStrategy = require('passport-google-oauth20').Strategy; +var LocalStrategy = require('passport-local').Strategy; +var validator = require('validator'); //core var config = require('./config.js'); @@ -35,12 +37,10 @@ function callback(accessToken, refreshToken, profile, done) { if (user.accessToken != accessToken) { user.accessToken = accessToken; needSave = true; - } if (user.refreshToken != refreshToken) { user.refreshToken = refreshToken; needSave = true; - } if (needSave) { user.save().then(function () { @@ -57,7 +57,7 @@ function callback(accessToken, refreshToken, profile, done) { }).catch(function (err) { logger.error('auth callback failed: ' + err); return done(err, null); - }) + }); } //facebook @@ -109,4 +109,25 @@ if (config.google) { clientSecret: config.google.clientSecret, callbackURL: config.serverurl + '/auth/google/callback' }, callback)); +} +// email +if (config.email) { + passport.use(new LocalStrategy({ + usernameField: 'email' + }, + function(email, password, done) { + if (!validator.isEmail(email)) return done(null, false); + models.User.findOne({ + where: { + email: email + } + }).then(function (user) { + if (!user) return done(null, false); + if (!user.verifyPassword(password)) return done(null, false); + return done(null, user); + }).catch(function (err) { + logger.error(err); + return done(err); + }); + })); }
\ No newline at end of file diff --git a/lib/config.js b/lib/config.js index a906dfa4..669fcaa8 100644 --- a/lib/config.js +++ b/lib/config.js @@ -94,6 +94,7 @@ var google = (process.env.HMD_GOOGLE_CLIENTID && process.env.HMD_GOOGLE_CLIENTSE clientSecret: process.env.HMD_GOOGLE_CLIENTSECRET } : config.google || false; var imgur = process.env.HMD_IMGUR_CLIENTID || config.imgur || false; +var email = process.env.HMD_EMAIL || config.email || false; function getserverurl() { var url = ''; @@ -151,6 +152,7 @@ module.exports = { dropbox: dropbox, google: google, imgur: imgur, + email: email, imageUploadType: imageUploadType, s3: s3, s3bucket: s3bucket diff --git a/lib/migrations/20161201050312-support-email-signin.js b/lib/migrations/20161201050312-support-email-signin.js new file mode 100644 index 00000000..bdea7c8c --- /dev/null +++ b/lib/migrations/20161201050312-support-email-signin.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = { + up: function (queryInterface, Sequelize) { + queryInterface.addColumn('Users', 'email', Sequelize.TEXT); + queryInterface.addColumn('Users', 'password', Sequelize.TEXT); + }, + + down: function (queryInterface, Sequelize) { + queryInterface.removeColumn('Users', 'email', Sequelize.TEXT); + queryInterface.removeColumn('Users', 'password', Sequelize.TEXT); + } +}; diff --git a/lib/models/user.js b/lib/models/user.js index 7272f688..aaf344de 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -3,6 +3,7 @@ // external modules var md5 = require("blueimp-md5"); var Sequelize = require("sequelize"); +var scrypt = require('scrypt'); // core var logger = require("../logger.js"); @@ -29,8 +30,30 @@ module.exports = function (sequelize, DataTypes) { }, refreshToken: { type: DataTypes.STRING + }, + email: { + type: Sequelize.TEXT, + validate: { + isEmail: true + } + }, + password: { + type: Sequelize.TEXT, + set: function(value) { + var hash = scrypt.kdfSync(value, scrypt.paramsSync(0.1)).toString("hex"); + this.setDataValue('password', hash); + } } }, { + instanceMethods: { + verifyPassword: function(attempt) { + if (scrypt.verifyKdfSync(new Buffer(this.password, "hex"), attempt)) { + return this; + } else { + return false; + } + } + }, classMethods: { associate: function (models) { User.hasMany(models.Note, { @@ -42,6 +65,9 @@ module.exports = function (sequelize, DataTypes) { constraints: false }); }, + getProfile: function (user) { + return user.profile ? User.parseProfile(user.profile) : (user.email ? User.parseProfileByEmail(user.email) : null); + }, parseProfile: function (profile) { try { var profile = JSON.parse(profile); @@ -81,6 +107,13 @@ module.exports = function (sequelize, DataTypes) { break; } return photo; + }, + parseProfileByEmail: function (email) { + var photoUrl = 'https://www.gravatar.com/avatar/' + md5(email); + return { + name: email.substring(0, email.lastIndexOf("@")), + photo: photoUrl += '?s=96' + }; } } }); diff --git a/lib/realtime.js b/lib/realtime.js index b50e05b2..73f831f4 100644 --- a/lib/realtime.js +++ b/lib/realtime.js @@ -131,7 +131,7 @@ function updateNote(note, callback) { } }).then(function (user) { if (!user) return callback(null, null); - note.lastchangeuserprofile = models.User.parseProfile(user.profile); + note.lastchangeuserprofile = models.User.getProfile(user); return finishUpdateNote(note, _note, callback); }).catch(function (err) { logger.error(err); @@ -455,10 +455,10 @@ function startConnection(socket) { return failConnection(404, 'note not found', socket); } var owner = note.ownerId; - var ownerprofile = note.owner ? models.User.parseProfile(note.owner.profile) : null; + var ownerprofile = note.owner ? models.User.getProfile(note.owner) : null; var lastchangeuser = note.lastchangeuserId; - var lastchangeuserprofile = note.lastchangeuser ? models.User.parseProfile(note.lastchangeuser.profile) : null; + var lastchangeuserprofile = note.lastchangeuser ? models.User.getProfile(note.lastchangeuser) : null; var body = LZString.decompressFromBase64(note.content); var createtime = note.createdAt; @@ -468,7 +468,7 @@ function startConnection(socket) { var authors = {}; for (var i = 0; i < note.authors.length; i++) { var author = note.authors[i]; - var profile = models.User.parseProfile(author.user.profile); + var profile = models.User.getProfile(author.user); authors[author.userId] = { userid: author.userId, color: author.color, @@ -598,7 +598,7 @@ function buildUserOutData(user) { function updateUserData(socket, user) { //retrieve user data from passport if (socket.request.user && socket.request.user.logged_in) { - var profile = models.User.parseProfile(socket.request.user.profile); + var profile = models.User.getProfile(socket.request.user); user.photo = profile.photo; user.name = profile.name; user.userid = socket.request.user.id; diff --git a/lib/response.js b/lib/response.js index 0004f824..aae39851 100755 --- a/lib/response.js +++ b/lib/response.js @@ -66,7 +66,10 @@ function showIndex(req, res, next) { gitlab: config.gitlab, dropbox: config.dropbox, google: config.google, - signin: req.isAuthenticated() + email: config.email, + signin: req.isAuthenticated(), + infoMessage: req.flash('info'), + errorMessage: req.flash('error') }); } @@ -94,7 +97,8 @@ function responseHackMD(res, note) { github: config.github, gitlab: config.gitlab, dropbox: config.dropbox, - google: config.google + google: config.google, + email: config.email }); } @@ -202,9 +206,9 @@ function showPublishNote(req, res, next) { body: body, useCDN: config.usecdn, owner: note.owner ? note.owner.id : null, - ownerprofile: note.owner ? models.User.parseProfile(note.owner.profile) : null, + ownerprofile: note.owner ? models.User.getProfile(note.owner) : null, lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null, - lastchangeuserprofile: note.lastchangeuser ? models.User.parseProfile(note.lastchangeuser.profile) : null, + lastchangeuserprofile: note.lastchangeuser ? models.User.getProfile(note.lastchangeuser) : null, robots: meta.robots || false, //default allow robots GA: meta.GA, disqus: meta.disqus @@ -591,9 +595,9 @@ function showPublishSlide(req, res, next) { meta: JSON.stringify(obj.meta || {}), useCDN: config.usecdn, owner: note.owner ? note.owner.id : null, - ownerprofile: note.owner ? models.User.parseProfile(note.owner.profile) : null, + ownerprofile: note.owner ? models.User.getProfile(note.owner) : null, lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null, - lastchangeuserprofile: note.lastchangeuser ? models.User.parseProfile(note.lastchangeuser.profile) : null, + lastchangeuserprofile: note.lastchangeuser ? models.User.getProfile(note.lastchangeuser) : null, robots: meta.robots || false, //default allow robots GA: meta.GA, disqus: meta.disqus |