river-of-ebooks/api/helpers/passport.js

182 lines
5.2 KiB
JavaScript
Raw Normal View History

2018-11-02 00:21:36 +00:00
// api/helpers/passport.js
// from https://github.com/trailsjs/sails-auth/blob/master/api/services/passport.js
2018-11-07 20:06:36 +00:00
const url = require('url')
2019-03-05 23:55:31 +00:00
const { generateToken } = require('../util')
2018-11-02 00:21:36 +00:00
module.exports = {
friendlyName: 'Load PassportHelper',
description: 'Load a PassportHelper instance',
inputs: {},
exits: {
success: {
outputFriendlyName: 'Passport helper',
outputDescription: 'A PassportHelper instance'
}
},
fn: async function (inputs, exits) {
2018-11-07 20:06:36 +00:00
return exits.success(new PassportHelper())
2018-11-02 00:21:36 +00:00
}
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
2018-11-07 20:06:36 +00:00
const passport = require('passport')
2018-11-12 22:12:16 +00:00
passport.serializeUser(function (user, next) {
2018-11-07 20:06:36 +00:00
next(null, user.id)
})
2018-11-12 22:12:16 +00:00
passport.deserializeUser(function (id, next) {
return User.findOne({ id: id })
2018-11-12 22:12:16 +00:00
.then(function (user) {
2018-11-07 20:06:36 +00:00
next(null, user)
return user
}).catch(next)
})
2018-11-02 00:21:36 +00:00
function PassportHelper () {
2018-11-07 20:06:36 +00:00
this.protocols = sails.config.protocols
2018-11-02 00:21:36 +00:00
this.loadStrategies = function () {
2018-11-07 20:06:36 +00:00
const strategies = sails.config.passport
2018-11-02 00:21:36 +00:00
for (const key in strategies) {
let options = { passReqToCallback: true }
2018-11-07 20:06:36 +00:00
let Strategy = strategies[key].strategy
2018-11-02 00:21:36 +00:00
if (key === 'local') {
_.extend(options, {
usernameField: 'identifier'
2018-11-07 20:06:36 +00:00
})
passport.use(new Strategy(options, this.protocols.local.login))
2018-11-02 00:21:36 +00:00
} else {
2018-11-07 20:06:36 +00:00
const protocol = strategies[key].protocol
const callbackURL = strategies[key].callback
let baseURL = ''
if (sails.config.custom.baseURL && sails.config.custom.baseURL !== null) {
baseURL = sails.config.custom.baseURL
2018-11-02 00:21:36 +00:00
} else {
2018-11-07 20:06:36 +00:00
sails.log.warn('Please add \'appUrl\' to configuration')
baseURL = sails.getBaseurl()
2018-11-02 00:21:36 +00:00
}
switch (protocol) {
case 'oauth2':
2018-11-07 20:06:36 +00:00
options.callbackURL = url.resolve(baseURL, callbackURL)
break
2018-11-02 00:21:36 +00:00
// other protocols (openid, etc can go here)
}
2018-11-07 20:06:36 +00:00
_.extend(options, strategies[key].options)
2018-11-02 00:21:36 +00:00
2018-11-07 20:06:36 +00:00
passport.use(new Strategy(options, this.protocols[protocol].login))
2018-11-02 00:21:36 +00:00
}
}
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
this.endpoint = function (req, res) {
2018-11-07 20:06:36 +00:00
const strategies = sails.config.passport
const provider = req.param('provider')
2018-11-02 00:21:36 +00:00
2018-11-12 22:12:16 +00:00
if (!_.has(strategies, provider)) return res.redirect('/login')
2018-11-02 00:21:36 +00:00
const scopes = {
google: ['email'],
github: ['user:email']
}
passport.authenticate(provider, { scope: scopes[provider] })(req, res, req.next)
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
// a callback helper to split by req
this.callback = function (req, res, next) {
2018-11-07 20:06:36 +00:00
var provider = req.param('provider', 'local')
var action = req.param('action')
2018-11-02 00:21:36 +00:00
if (provider === 'local' && action !== undefined) {
if (action === 'register' && !req.user) {
2018-11-07 20:06:36 +00:00
this.protocols.local.register(req, res, next)
2018-11-02 00:21:36 +00:00
} else if (action === 'connect' && req.user) {
2018-11-07 20:06:36 +00:00
this.protocols.local.connect(req, res, next)
2018-11-02 00:21:36 +00:00
} else if (action === 'disconnect' && req.user) {
2018-11-07 20:06:36 +00:00
this.protocols.local.disconnect(req, res, next)
2018-11-02 00:21:36 +00:00
} else {
2018-11-12 22:12:16 +00:00
next(new Error('Invalid action'))
2018-11-02 00:21:36 +00:00
}
} else {
if (action === 'disconnect' && req.user) {
2018-11-07 20:06:36 +00:00
this.disconnect(req, res, next)
2018-11-02 00:21:36 +00:00
} else {
2018-11-07 20:06:36 +00:00
passport.authenticate(provider, next)(req, res, req.next)
2018-11-02 00:21:36 +00:00
}
}
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
this.connect = async function (req, q, profile, next) {
2018-11-07 20:06:36 +00:00
let userAttrs = {}
let provider = profile.provider || req.param('provider')
2018-11-02 00:21:36 +00:00
2018-11-07 20:06:36 +00:00
req.session.tokens = q.tokens
q.provider = provider
2018-11-02 00:21:36 +00:00
if (!provider) {
2018-11-07 20:06:36 +00:00
return next(new Error('No provider identified'))
2018-11-02 00:21:36 +00:00
}
// if the profile object from passport has an email, use it
2018-11-12 22:12:16 +00:00
if (profile.emails && profile.emails[0]) userAttrs.email = profile.emails[0].value
// if (!userAttrs.email) return next(new Error('No email available'))
2018-11-02 00:21:36 +00:00
2018-11-12 22:12:16 +00:00
const pass = await Passport.findOne({
2018-11-02 00:21:36 +00:00
provider,
identifier: q.identifier
2018-11-07 20:06:36 +00:00
})
2018-11-02 00:21:36 +00:00
2018-11-07 20:06:36 +00:00
let user
2018-11-02 00:21:36 +00:00
if (!req.user) {
if (!pass) { // new user signing up, create a new user and/or passport
if (userAttrs.email) {
user = await User.findOne({ email: userAttrs.email })
}
if (!user) {
2019-03-06 00:56:55 +00:00
user = await User.create({ userAttrs, signing_secret: await generateToken({ bytes: 24 }) }).fetch()
}
2018-11-02 00:21:36 +00:00
await Passport.create({
...q,
user: user.id
2018-11-07 20:06:36 +00:00
})
2018-11-12 22:12:16 +00:00
next(null, user)
2018-11-02 00:21:36 +00:00
} else { // existing user logging in
if (_.has(q, 'tokens') && q.tokens !== pass.tokens) {
pass.tokens = q.tokens
2018-11-02 00:21:36 +00:00
}
await Passport.update({ id: pass.id }, { tokens: pass.tokens })
2019-03-25 18:08:30 +00:00
user = await User.find({ id: pass.user }).limit(1)
next(null, user[0])
2018-11-02 00:21:36 +00:00
}
} else { // user logged in and trying to add new Passport
if (!pass) {
2018-11-02 00:21:36 +00:00
await Passport.create({
...q,
user: req.user.id
2018-11-07 20:06:36 +00:00
})
2018-11-12 22:12:16 +00:00
next(null, req.user)
2018-11-02 00:21:36 +00:00
} else { // no action, user already logged in and passport exists
2018-11-12 22:12:16 +00:00
next(null, user)
2018-11-02 00:21:36 +00:00
}
}
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
this.disconnect = async function (req, res, next) {
try {
2018-11-07 20:06:36 +00:00
const user = req.user
const provider = req.param('provider')
2018-11-02 00:21:36 +00:00
const pass = Passport.findOne({
provider,
user: user.id
2018-11-07 20:06:36 +00:00
})
await Passport.destroy(pass.id)
next(null, user)
return user
2018-11-02 00:21:36 +00:00
} catch (e) {
2018-11-12 22:12:16 +00:00
next(e)
2018-11-02 00:21:36 +00:00
}
2018-11-07 20:06:36 +00:00
}
2018-11-02 00:21:36 +00:00
this.getPassport = function () {
2018-11-07 20:06:36 +00:00
return passport
}
}