codecombat/server/routes/auth.coffee

184 lines
6.9 KiB
CoffeeScript
Raw Normal View History

2014-06-30 22:16:26 -04:00
authentication = require 'passport'
2014-01-03 13:32:13 -05:00
LocalStrategy = require('passport-local').Strategy
2014-06-30 22:16:26 -04:00
User = require '../users/User'
UserHandler = require '../users/user_handler'
LevelSession = require '../levels/sessions/LevelSession'
config = require '../../server_config'
errors = require '../commons/errors'
mail = require '../commons/mail'
languages = require '../routes/languages'
2014-01-03 13:32:13 -05:00
module.exports.setup = (app) ->
2014-02-04 17:08:20 -05:00
authentication.serializeUser((user, done) -> done(null, user._id))
authentication.deserializeUser((id, done) ->
2014-01-03 13:32:13 -05:00
User.findById(id, (err, user) -> done(err, user)))
2014-02-04 17:08:20 -05:00
authentication.use(new LocalStrategy(
2014-01-03 13:32:13 -05:00
(username, password, done) ->
2014-06-30 22:16:26 -04:00
User.findOne({emailLower: username.toLowerCase()}).exec((err, user) ->
2014-01-03 13:32:13 -05:00
return done(err) if err
2014-06-30 22:16:26 -04:00
return done(null, false, {message: 'not found', property: 'email'}) if not user
2014-01-03 13:32:13 -05:00
passwordReset = (user.get('passwordReset') or '').toLowerCase()
if passwordReset and password.toLowerCase() is passwordReset
User.update {_id: user.get('_id')}, {passwordReset: ''}, {}, ->
return done(null, user)
2014-01-03 13:32:13 -05:00
hash = User.hashPassword(password)
unless user.get('passwordHash') is hash
2014-06-30 22:16:26 -04:00
return done(null, false, {message: 'is wrong.', property: 'password'})
2014-01-03 13:32:13 -05:00
return done(null, user)
)
))
2014-06-30 22:16:26 -04:00
2014-02-26 17:14:43 -05:00
app.post '/auth/spy', (req, res, next) ->
if req?.user?.isAdmin()
2014-02-26 17:14:43 -05:00
username = req.body.usernameLower
emailLower = req.body.emailLower
if emailLower
2014-06-30 22:16:26 -04:00
query = {'emailLower': emailLower}
2014-02-26 17:14:43 -05:00
else if username
2014-06-30 22:16:26 -04:00
query = {'nameLower': username}
2014-02-26 17:14:43 -05:00
else
2014-06-30 22:16:26 -04:00
return errors.badInput res, 'You need to supply one of emailLower or username'
2014-02-26 17:14:43 -05:00
User.findOne query, (err, user) ->
2014-06-30 22:16:26 -04:00
if err? then return errors.serverError res, 'There was an error finding the specified user'
2014-06-30 22:16:26 -04:00
unless user then return errors.badInput res, 'The specified user couldn\'t be found'
2014-02-26 17:14:43 -05:00
req.logIn user, (err) ->
2014-06-30 22:16:26 -04:00
if err? then return errors.serverError res, 'There was an error logging in with the specified'
2014-02-26 17:14:43 -05:00
res.send(UserHandler.formatEntity(req, user))
return res.end()
else
2014-06-30 22:16:26 -04:00
return errors.unauthorized res, 'You must be an admin to enter espionage mode'
2014-01-03 13:32:13 -05:00
app.post('/auth/login', (req, res, next) ->
2014-02-04 17:08:20 -05:00
authentication.authenticate('local', (err, user, info) ->
2014-01-03 13:32:13 -05:00
return next(err) if err
if not user
2014-06-30 22:16:26 -04:00
return errors.unauthorized(res, [{message: info.message, property: info.property}])
2014-01-03 13:32:13 -05:00
req.logIn(user, (err) ->
return next(err) if (err)
activity = req.user.trackActivity 'login', 1
user.update {activity: activity}, (err) ->
return next(err) if (err)
res.send(UserHandler.formatEntity(req, req.user))
return res.end()
2014-01-03 13:32:13 -05:00
)
)(req, res, next)
)
app.get('/auth/whoami', (req, res) ->
if req.user
sendSelf(req, res)
else
user = makeNewUser(req)
makeNext = (req, res) -> -> sendSelf(req, res)
next = makeNext(req, res)
loginUser(req, res, user, false, next)
)
sendSelf = (req, res) ->
res.setHeader('Content-Type', 'text/json')
2014-01-03 13:32:13 -05:00
res.send(UserHandler.formatEntity(req, req.user))
res.end()
2014-01-03 13:32:13 -05:00
app.post('/auth/logout', (req, res) ->
req.logout()
res.end()
)
2014-01-03 13:32:13 -05:00
app.post('/auth/reset', (req, res) ->
unless req.body.email
2014-06-30 22:16:26 -04:00
return errors.badInput(res, [{message: 'Need an email specified.', property: 'email'}])
2014-06-30 22:16:26 -04:00
User.findOne({emailLower: req.body.email.toLowerCase()}).exec((err, user) ->
2014-01-03 13:32:13 -05:00
if not user
2014-06-30 22:16:26 -04:00
return errors.notFound(res, [{message: 'not found.', property: 'email'}])
2014-06-30 22:16:26 -04:00
user.set('passwordReset', Math.random().toString(36).slice(2, 7).toUpperCase())
2014-01-03 13:32:13 -05:00
user.save (err) =>
return errors.serverError(res) if err
if config.isProduction
2014-01-03 13:32:13 -05:00
options = createMailOptions req.body.email, user.get('passwordReset')
mail.transport.sendMail options, (error, response) ->
2014-01-03 13:32:13 -05:00
if error
console.error "Error sending mail: #{error.message or error}"
return errors.serverError(res) if err
2014-01-03 13:32:13 -05:00
else
return res.end()
2014-01-06 15:14:12 -05:00
else
console.log 'password is', user.get('passwordReset')
2014-02-02 18:02:47 -05:00
res.send user.get('passwordReset')
2014-01-06 15:14:12 -05:00
return res.end()
2014-01-03 13:32:13 -05:00
)
)
2014-01-17 13:47:42 -05:00
app.get '/auth/unsubscribe', (req, res) ->
email = req.query.email
unless req.query.email
return errors.badInput res, 'No email provided to unsubscribe.'
if req.query.session
# Unsubscribe from just one session's notifications instead.
return LevelSession.findOne({_id: req.query.session}).exec (err, session) ->
return errors.serverError res, 'Could not unsubscribe: #{req.query.session}, #{req.query.email}: #{err}' if err
session.set 'unsubscribed', true
session.save (err) ->
return errors.serverError res, 'Database failure.' if err
res.send "Unsubscribed #{req.query.email} from CodeCombat emails for #{session.levelName} #{session.team} ladder updates. Sorry to see you go! <p><a href='/play/ladder/#{session.levelID}#my-matches'>Ladder preferences</a></p>"
res.end()
2014-06-30 22:16:26 -04:00
User.findOne({emailLower: req.query.email.toLowerCase()}).exec (err, user) ->
2014-01-17 13:47:42 -05:00
if not user
return errors.notFound res, "No user found with email '#{req.query.email}'"
emails = _.clone(user.get('emails')) or {}
msg = ''
if req.query.recruitNotes
emails.recruitNotes ?= {}
emails.recruitNotes.enabled = false
msg = "Unsubscribed #{req.query.email} from recruiting emails."
else
msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!"
emailSettings.enabled = false for emailSettings in _.values(emails)
emails.generalNews ?= {}
emails.generalNews.enabled = false
emails.anyNotes ?= {}
emails.anyNotes.enabled = false
user.update {$set: {emails: emails}}, {}, =>
2014-01-17 13:47:42 -05:00
return errors.serverError res, 'Database failure.' if err
2014-06-30 22:16:26 -04:00
res.send msg + '<p><a href="/account/settings">Account settings</a></p>'
2014-01-17 13:47:42 -05:00
res.end()
2014-01-03 13:32:13 -05:00
module.exports.loginUser = loginUser = (req, res, user, send=true, next=null) ->
user.save((err) ->
2014-07-10 04:07:36 -04:00
return errors.serverError res, err if err?
req.logIn(user, (err) ->
2014-07-10 04:07:36 -04:00
return errors.serverError res, err if err?
return res.send user if send
next() if next
)
)
module.exports.makeNewUser = makeNewUser = (req) ->
2014-06-30 22:16:26 -04:00
user = new User({anonymous: true})
user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth
user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages
2014-01-03 13:32:13 -05:00
createMailOptions = (receiver, password) ->
# TODO: use email templates here
options =
from: config.mail.username
to: receiver
replyTo: config.mail.username
2014-06-30 22:16:26 -04:00
subject: '[CodeCombat] Password Reset'
2014-01-03 13:32:13 -05:00
text: "You can log into your account with: #{password}"