diff --git a/app.js b/app.js index f0ccd7d48..bfa7d356e 100644 --- a/app.js +++ b/app.js @@ -29,7 +29,6 @@ var getImageMimeType = require('./lib/utils.js').getImageMimeType // core var config = require('./lib/config.js') var logger = require('./lib/logger.js') -var auth = require('./lib/auth.js') var response = require('./lib/response.js') var models = require('./lib/models') @@ -165,7 +164,6 @@ app.use(flash()) // passport app.use(passport.initialize()) app.use(passport.session()) -auth.registerAuthMethod() // serialize and deserialize passport.serializeUser(function (user, done) { @@ -200,164 +198,10 @@ app.engine('ejs', ejs.renderFile) // set view engine app.set('view engine', 'ejs') -function setReturnToFromReferer (req) { - var referer = req.get('referer') - if (!req.session) req.session = {} - req.session.returnTo = referer -} - -// facebook auth -if (config.facebook) { - app.get('/auth/facebook', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('facebook')(req, res, next) - }) - // facebook auth callback - app.get('/auth/facebook/callback', - passport.authenticate('facebook', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) -} -// twitter auth -if (config.twitter) { - app.get('/auth/twitter', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('twitter')(req, res, next) - }) - // twitter auth callback - app.get('/auth/twitter/callback', - passport.authenticate('twitter', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) -} -// github auth -if (config.github) { - app.get('/auth/github', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('github')(req, res, next) - }) - // github auth callback - app.get('/auth/github/callback', - passport.authenticate('github', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) - if (!config.gitlab.scope || config.gitlab.scope === 'api') { - // gitlab callback actions - app.get('/auth/gitlab/callback/:noteId/:action', response.gitlabActions) - } -} -// gitlab auth -if (config.gitlab) { - app.get('/auth/gitlab', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('gitlab')(req, res, next) - }) - // gitlab auth callback - app.get('/auth/gitlab/callback', - passport.authenticate('gitlab', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) - // gitlab callback actions - app.get('/auth/gitlab/callback/:noteId/:action', response.gitlabActions) -} -// dropbox auth -if (config.dropbox) { - app.get('/auth/dropbox', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('dropbox-oauth2')(req, res, next) - }) - // dropbox auth callback - app.get('/auth/dropbox/callback', - passport.authenticate('dropbox-oauth2', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) -} -// google auth -if (config.google) { - app.get('/auth/google', function (req, res, next) { - setReturnToFromReferer(req) - passport.authenticate('google', { scope: ['profile'] })(req, res, next) - }) - // google auth callback - app.get('/auth/google/callback', - passport.authenticate('google', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/' - })) -} -// ldap auth -if (config.ldap) { - app.post('/auth/ldap', urlencodedParser, function (req, res, next) { - if (!req.body.username || !req.body.password) return response.errorBadRequest(res) - setReturnToFromReferer(req) - passport.authenticate('ldapauth', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/', - failureFlash: true - })(req, res, next) - }) -} -// email auth -if (config.email) { - if (config.allowemailregister) { - app.post('/register', urlencodedParser, function (req, res, next) { - if (!req.body.email || !req.body.password) return response.errorBadRequest(res) - if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) - models.User.findOrCreate({ - where: { - email: req.body.email - }, - defaults: { - password: req.body.password - } - }).spread(function (user, created) { - if (user) { - if (created) { - if (config.debug) { - logger.info('user registered: ' + user.id) - } - req.flash('info', "You've successfully registered, please signin.") - } else { - if (config.debug) { - logger.info('user found: ' + user.id) - } - req.flash('error', 'This email has been used, please try another one.') - } - return res.redirect(config.serverurl + '/') - } - req.flash('error', 'Failed to register your account, please try again.') - return res.redirect(config.serverurl + '/') - }).catch(function (err) { - logger.error('auth callback failed: ' + err) - return response.errorInternalError(res) - }) - }) - } app.use(require('./lib/web/baseRouter')) app.use(require('./lib/web/statusRouter')) +app.use(require('./lib/web/auth')) - app.post('/login', urlencodedParser, function (req, res, next) { - if (!req.body.email || !req.body.password) return response.errorBadRequest(res) - if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) - setReturnToFromReferer(req) - passport.authenticate('local', { - successReturnToOrRedirect: config.serverurl + '/', - failureRedirect: config.serverurl + '/', - failureFlash: 'Invalid email or password.' - })(req, res, next) - }) -} -// logout -app.get('/logout', function (req, res) { - if (config.debug && req.isAuthenticated()) { logger.info('user logout: ' + req.user.id) } - req.logout() - res.redirect(config.serverurl + '/') -}) var history = require('./lib/history.js') // get history app.get('/history', history.historyGet) diff --git a/lib/auth.js b/lib/auth.js deleted file mode 100644 index 3e129b957..000000000 --- a/lib/auth.js +++ /dev/null @@ -1,194 +0,0 @@ -'use strict' -// auth -// external modules -var passport = require('passport') -var FacebookStrategy = require('passport-facebook').Strategy -var TwitterStrategy = require('passport-twitter').Strategy -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 LdapStrategy = require('passport-ldapauth') -var LocalStrategy = require('passport-local').Strategy -var validator = require('validator') - -// core -var config = require('./config.js') -var logger = require('./logger.js') -var models = require('./models') - -function callback (accessToken, refreshToken, profile, done) { - // logger.info(profile.displayName || profile.username); - var stringifiedProfile = JSON.stringify(profile) - models.User.findOrCreate({ - where: { - profileid: profile.id.toString() - }, - defaults: { - profile: stringifiedProfile, - accessToken: accessToken, - refreshToken: refreshToken - } - }).spread(function (user, created) { - if (user) { - var needSave = false - if (user.profile !== stringifiedProfile) { - user.profile = stringifiedProfile - needSave = true - } - if (user.accessToken !== accessToken) { - user.accessToken = accessToken - needSave = true - } - if (user.refreshToken !== refreshToken) { - user.refreshToken = refreshToken - needSave = true - } - if (needSave) { - user.save().then(function () { - if (config.debug) { logger.info('user login: ' + user.id) } - return done(null, user) - }) - } else { - if (config.debug) { logger.info('user login: ' + user.id) } - return done(null, user) - } - } - }).catch(function (err) { - logger.error('auth callback failed: ' + err) - return done(err, null) - }) -} - -function registerAuthMethod () { -// facebook - if (config.facebook) { - passport.use(new FacebookStrategy({ - clientID: config.facebook.clientID, - clientSecret: config.facebook.clientSecret, - callbackURL: config.serverurl + '/auth/facebook/callback' - }, callback)) - } -// twitter - if (config.twitter) { - passport.use(new TwitterStrategy({ - consumerKey: config.twitter.consumerKey, - consumerSecret: config.twitter.consumerSecret, - callbackURL: config.serverurl + '/auth/twitter/callback' - }, callback)) - } -// github - if (config.github) { - passport.use(new GithubStrategy({ - clientID: config.github.clientID, - clientSecret: config.github.clientSecret, - callbackURL: config.serverurl + '/auth/github/callback' - }, callback)) - } -// gitlab - if (config.gitlab) { - passport.use(new GitlabStrategy({ - baseURL: config.gitlab.baseURL, - clientID: config.gitlab.clientID, - clientSecret: config.gitlab.clientSecret, - scope: config.gitlab.scope, - callbackURL: config.serverurl + '/auth/gitlab/callback' - }, callback)) - } -// dropbox - if (config.dropbox) { - passport.use(new DropboxStrategy({ - apiVersion: '2', - clientID: config.dropbox.clientID, - clientSecret: config.dropbox.clientSecret, - callbackURL: config.serverurl + '/auth/dropbox/callback' - }, callback)) - } -// google - if (config.google) { - passport.use(new GoogleStrategy({ - clientID: config.google.clientID, - clientSecret: config.google.clientSecret, - callbackURL: config.serverurl + '/auth/google/callback' - }, callback)) - } -// ldap - if (config.ldap) { - passport.use(new LdapStrategy({ - server: { - url: config.ldap.url || null, - bindDn: config.ldap.bindDn || null, - bindCredentials: config.ldap.bindCredentials || null, - searchBase: config.ldap.searchBase || null, - searchFilter: config.ldap.searchFilter || null, - searchAttributes: config.ldap.searchAttributes || null, - tlsOptions: config.ldap.tlsOptions || null - } - }, - function (user, done) { - var profile = { - id: 'LDAP-' + user.uidNumber, - username: user.uid, - displayName: user.displayName, - emails: user.mail ? [user.mail] : [], - avatarUrl: null, - profileUrl: null, - provider: 'ldap' - } - var stringifiedProfile = JSON.stringify(profile) - models.User.findOrCreate({ - where: { - profileid: profile.id.toString() - }, - defaults: { - profile: stringifiedProfile - } - }).spread(function (user, created) { - if (user) { - var needSave = false - if (user.profile !== stringifiedProfile) { - user.profile = stringifiedProfile - needSave = true - } - if (needSave) { - user.save().then(function () { - if (config.debug) { logger.info('user login: ' + user.id) } - return done(null, user) - }) - } else { - if (config.debug) { logger.info('user login: ' + user.id) } - return done(null, user) - } - } - }).catch(function (err) { - logger.error('ldap auth failed: ' + err) - return done(err, null) - }) - })) - } -// 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) - }) - })) - } -} - -module.exports = { - registerAuthMethod: registerAuthMethod -} diff --git a/lib/web/auth/dropbox/index.js b/lib/web/auth/dropbox/index.js new file mode 100644 index 000000000..c03fbc57d --- /dev/null +++ b/lib/web/auth/dropbox/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const DropboxStrategy = require('passport-dropbox-oauth2').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let dropboxAuth = module.exports = Router() + +passport.use(new DropboxStrategy({ + apiVersion: '2', + clientID: config.dropbox.clientID, + clientSecret: config.dropbox.clientSecret, + callbackURL: config.serverurl + '/auth/dropbox/callback' +}, passportGeneralCallback)) + +dropboxAuth.get('/auth/dropbox', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('dropbox-oauth2')(req, res, next) +}) + +// dropbox auth callback +dropboxAuth.get('/auth/dropbox/callback', + passport.authenticate('dropbox-oauth2', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/email/index.js b/lib/web/auth/email/index.js new file mode 100644 index 000000000..760075f85 --- /dev/null +++ b/lib/web/auth/email/index.js @@ -0,0 +1,74 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const validator = require('validator') +const LocalStrategy = require('passport-local').Strategy +const config = require('../../../config') +const models = require('../../../models') +const logger = require('../../../logger') +const {setReturnToFromReferer} = require('../utils') +const {urlencodedParser} = require('../../utils') +const response = require('../../../response') + +let emailAuth = module.exports = Router() + +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) + }) +})) + +if (config.allowemailregister) { + emailAuth.post('/register', urlencodedParser, function (req, res, next) { + if (!req.body.email || !req.body.password) return response.errorBadRequest(res) + if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) + models.User.findOrCreate({ + where: { + email: req.body.email + }, + defaults: { + password: req.body.password + } + }).spread(function (user, created) { + if (user) { + if (created) { + logger.debug('user registered: ' + user.id) + req.flash('info', "You've successfully registered, please signin.") + } else { + logger.debug('user found: ' + user.id) + req.flash('error', 'This email has been used, please try another one.') + } + return res.redirect(config.serverurl + '/') + } + req.flash('error', 'Failed to register your account, please try again.') + return res.redirect(config.serverurl + '/') + }).catch(function (err) { + logger.error('auth callback failed: ' + err) + return response.errorInternalError(res) + }) + }) +} + +emailAuth.post('/login', urlencodedParser, function (req, res, next) { + if (!req.body.email || !req.body.password) return response.errorBadRequest(res) + if (!validator.isEmail(req.body.email)) return response.errorBadRequest(res) + setReturnToFromReferer(req) + passport.authenticate('local', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/', + failureFlash: 'Invalid email or password.' + })(req, res, next) +}) diff --git a/lib/web/auth/facebook/index.js b/lib/web/auth/facebook/index.js new file mode 100644 index 000000000..0e5474d8c --- /dev/null +++ b/lib/web/auth/facebook/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const FacebookStrategy = require('passport-facebook').Strategy + +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let facebookAuth = module.exports = Router() + +passport.use(new FacebookStrategy({ + clientID: config.facebook.clientID, + clientSecret: config.facebook.clientSecret, + callbackURL: config.serverurl + '/auth/facebook/callback' +}, passportGeneralCallback)) + +facebookAuth.get('/auth/facebook', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('facebook')(req, res, next) +}) + +// facebook auth callback +facebookAuth.get('/auth/facebook/callback', + passport.authenticate('facebook', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/github/index.js b/lib/web/auth/github/index.js new file mode 100644 index 000000000..2a26669cd --- /dev/null +++ b/lib/web/auth/github/index.js @@ -0,0 +1,28 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const GithubStrategy = require('passport-github').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let githubAuth = module.exports = Router() + +passport.use(new GithubStrategy({ + clientID: config.github.clientID, + clientSecret: config.github.clientSecret, + callbackURL: config.serverurl + '/auth/github/callback' +}, passportGeneralCallback)) + +githubAuth.get('/auth/github', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('github')(req, res, next) +}) + +// github auth callback +githubAuth.get('/auth/github/callback', + passport.authenticate('github', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/gitlab/index.js b/lib/web/auth/gitlab/index.js new file mode 100644 index 000000000..51de1602e --- /dev/null +++ b/lib/web/auth/gitlab/index.js @@ -0,0 +1,36 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const GitlabStrategy = require('passport-gitlab2').Strategy +const config = require('../../../config') +const response = require('../../../response') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let gitlabAuth = module.exports = Router() + +passport.use(new GitlabStrategy({ + baseURL: config.gitlab.baseURL, + clientID: config.gitlab.clientID, + clientSecret: config.gitlab.clientSecret, + scope: config.gitlab.scope, + callbackURL: config.serverurl + '/auth/gitlab/callback' +}, passportGeneralCallback)) + +gitlabAuth.get('/auth/gitlab', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('gitlab')(req, res, next) +}) + +// gitlab auth callback +gitlabAuth.get('/auth/gitlab/callback', + passport.authenticate('gitlab', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) + +if (!config.gitlab.scope || config.gitlab.scope === 'api') { + // gitlab callback actions + gitlabAuth.get('/auth/gitlab/callback/:noteId/:action', response.gitlabActions) +} diff --git a/lib/web/auth/google/index.js b/lib/web/auth/google/index.js new file mode 100644 index 000000000..bf2a260f7 --- /dev/null +++ b/lib/web/auth/google/index.js @@ -0,0 +1,27 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +var GoogleStrategy = require('passport-google-oauth20').Strategy +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let facebookAuth = module.exports = Router() + +passport.use(new GoogleStrategy({ + clientID: config.google.clientID, + clientSecret: config.google.clientSecret, + callbackURL: config.serverurl + '/auth/google/callback' +}, passportGeneralCallback)) + +facebookAuth.get('/auth/google', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('google', { scope: ['profile'] })(req, res, next) +}) + // google auth callback +facebookAuth.get('/auth/google/callback', + passport.authenticate('google', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js new file mode 100644 index 000000000..3a2038000 --- /dev/null +++ b/lib/web/auth/index.js @@ -0,0 +1,26 @@ +'use strict' + +const Router = require('express').Router + +const config = require('../../config') +const logger = require('../../logger') + +const authRouter = module.exports = Router() + +if (config.facebook) authRouter.use('/', require('./facebook')) +if (config.twitter) authRouter.use('/', require('./twitter')) +if (config.github) authRouter.use('/', require('./github')) +if (config.gitlab) authRouter.use('/', require('./gitlab')) +if (config.dropbox) authRouter.use('/', require('./dropbox')) +if (config.google) authRouter.use('/', require('./google')) +if (config.ldap) authRouter.use('/', require('./ldap')) +if (config.email) authRouter.use('/', require('./email')) + +// logout +authRouter.get('/logout', function (req, res) { + if (config.debug && req.isAuthenticated()) { + logger.debug('user logout: ' + req.user.id) + } + req.logout() + res.redirect(config.serverurl + '/') +}) diff --git a/lib/web/auth/ldap/index.js b/lib/web/auth/ldap/index.js new file mode 100644 index 000000000..766c5cbcc --- /dev/null +++ b/lib/web/auth/ldap/index.js @@ -0,0 +1,74 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const LDAPStrategy = require('passport-ldapauth') +const config = require('../../../config') +const models = require('../../../models') +const logger = require('../../../logger') +const {setReturnToFromReferer} = require('../utils') +const {urlencodedParser} = require('../../utils') +const response = require('../../../response') + +let ldapAuth = module.exports = Router() + +passport.use(new LDAPStrategy({ + server: { + url: config.ldap.url || null, + bindDn: config.ldap.bindDn || null, + bindCredentials: config.ldap.bindCredentials || null, + searchBase: config.ldap.searchBase || null, + searchFilter: config.ldap.searchFilter || null, + searchAttributes: config.ldap.searchAttributes || null, + tlsOptions: config.ldap.tlsOptions || null + } +}, function (user, done) { + var profile = { + id: 'LDAP-' + user.uidNumber, + username: user.uid, + displayName: user.displayName, + emails: user.mail ? [user.mail] : [], + avatarUrl: null, + profileUrl: null, + provider: 'ldap' + } + var stringifiedProfile = JSON.stringify(profile) + models.User.findOrCreate({ + where: { + profileid: profile.id.toString() + }, + defaults: { + profile: stringifiedProfile + } + }).spread(function (user, created) { + if (user) { + var needSave = false + if (user.profile !== stringifiedProfile) { + user.profile = stringifiedProfile + needSave = true + } + if (needSave) { + user.save().then(function () { + if (config.debug) { logger.debug('user login: ' + user.id) } + return done(null, user) + }) + } else { + if (config.debug) { logger.debug('user login: ' + user.id) } + return done(null, user) + } + } + }).catch(function (err) { + logger.error('ldap auth failed: ' + err) + return done(err, null) + }) +})) + +ldapAuth.post('/auth/ldap', urlencodedParser, function (req, res, next) { + if (!req.body.username || !req.body.password) return response.errorBadRequest(res) + setReturnToFromReferer(req) + passport.authenticate('ldapauth', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/', + failureFlash: true + })(req, res, next) +}) diff --git a/lib/web/auth/twitter/index.js b/lib/web/auth/twitter/index.js new file mode 100644 index 000000000..5429522de --- /dev/null +++ b/lib/web/auth/twitter/index.js @@ -0,0 +1,29 @@ +'use strict' + +const Router = require('express').Router +const passport = require('passport') +const TwitterStrategy = require('passport-twitter').Strategy + +const config = require('../../../config') +const {setReturnToFromReferer, passportGeneralCallback} = require('../utils') + +let twitterAuth = module.exports = Router() + +passport.use(new TwitterStrategy({ + consumerKey: config.twitter.consumerKey, + consumerSecret: config.twitter.consumerSecret, + callbackURL: config.serverurl + '/auth/twitter/callback' +}, passportGeneralCallback)) + +twitterAuth.get('/auth/twitter', function (req, res, next) { + setReturnToFromReferer(req) + passport.authenticate('twitter')(req, res, next) +}) + +// twitter auth callback +twitterAuth.get('/auth/twitter/callback', + passport.authenticate('twitter', { + successReturnToOrRedirect: config.serverurl + '/', + failureRedirect: config.serverurl + '/' + }) +) diff --git a/lib/web/auth/utils.js b/lib/web/auth/utils.js new file mode 100644 index 000000000..ff7a12375 --- /dev/null +++ b/lib/web/auth/utils.js @@ -0,0 +1,53 @@ +'use strict' + +const models = require('../../models') +const config = require('../../config') +const logger = require('../../logger') + +exports.setReturnToFromReferer = function setReturnToFromReferer (req) { + var referer = req.get('referer') + if (!req.session) req.session = {} + req.session.returnTo = referer +} + +exports.passportGeneralCallback = function callback (accessToken, refreshToken, profile, done) { + var stringifiedProfile = JSON.stringify(profile) + models.User.findOrCreate({ + where: { + profileid: profile.id.toString() + }, + defaults: { + profile: stringifiedProfile, + accessToken: accessToken, + refreshToken: refreshToken + } + }).spread(function (user, created) { + if (user) { + var needSave = false + if (user.profile !== stringifiedProfile) { + user.profile = stringifiedProfile + needSave = true + } + if (user.accessToken !== accessToken) { + user.accessToken = accessToken + needSave = true + } + if (user.refreshToken !== refreshToken) { + user.refreshToken = refreshToken + needSave = true + } + if (needSave) { + user.save().then(function () { + if (config.debug) { logger.info('user login: ' + user.id) } + return done(null, user) + }) + } else { + if (config.debug) { logger.info('user login: ' + user.id) } + return done(null, user) + } + } + }).catch(function (err) { + logger.error('auth callback failed: ' + err) + return done(err, null) + }) +}