2014-02-04 17:08:20 -05:00
authentication = require ( ' passport ' )
2014-01-03 13:32:13 -05:00
LocalStrategy = require ( ' passport-local ' ) . Strategy
2014-01-22 17:57:41 -05:00
User = require ( ' ../users/User ' )
UserHandler = require ( ' ../users/user_handler ' )
2014-03-11 00:30:46 -04:00
LevelSession = require ' ../levels/sessions/LevelSession '
2014-01-22 15:46:44 -05:00
config = require ' ../../server_config '
2014-01-22 17:57:41 -05:00
errors = require ' ../commons/errors '
2014-01-24 14:47:14 -05:00
mail = require ' ../commons/mail '
2014-02-24 14:12:52 -05:00
languages = require ' ../routes/languages '
2014-01-03 13:32:13 -05:00
2014-02-04 16:29: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) ->
User . findOne ( { emailLower : username . toLowerCase ( ) } ) . exec ( (err, user) ->
return done ( err ) if err
return done ( null , false , { message : ' not found ' , property : ' email ' } ) if not user
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-03-11 00:30:46 -04:00
2014-01-03 13:32:13 -05:00
hash = User . hashPassword ( password )
unless user . get ( ' passwordHash ' ) is hash
2014-03-13 13:27:32 -04:00
return done ( null , false , { message : ' is wrong. ' , property : ' password ' } )
2014-01-03 13:32:13 -05:00
return done ( null , user )
)
) )
2014-02-26 17:14:43 -05:00
app . post ' /auth/spy ' , (req, res, next) ->
if req ? . user ? . isAdmin ( )
2014-03-11 00:30:46 -04:00
2014-02-26 17:14:43 -05:00
username = req . body . usernameLower
emailLower = req . body . emailLower
if emailLower
query = { " emailLower " : emailLower }
else if username
query = { " nameLower " : username }
else
return errors . badInput res , " You need to supply one of emailLower or username "
2014-03-11 00:30:46 -04:00
2014-02-26 17:14:43 -05:00
User . findOne query , (err, user) ->
if err ? then return errors . serverError res , " There was an error finding the specified user "
2014-03-11 00:30:46 -04:00
2014-02-26 17:14:43 -05:00
unless user then return errors . badInput res , " The specified user couldn ' t be found "
2014-03-11 00:30:46 -04:00
2014-02-26 17:14:43 -05:00
req . logIn user , (err) ->
if err ? then return errors . serverError res , " There was an error logging in with the specified "
res . send ( UserHandler . formatEntity ( req , user ) )
return res . end ( )
else
return errors . unauthorized res , " You must be an admin to enter espionage mode "
2014-03-11 00:30:46 -04:00
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-01-14 17:13:47 -05: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 )
2014-06-10 19:30:07 -04:00
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) ->
2014-02-24 14:12:52 -05:00
if req . user
sendSelf ( req , res )
else
2014-04-02 16:12:24 -04:00
user = makeNewUser ( req )
2014-02-24 14:12:52 -05:00
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-02-24 14:12:52 -05:00
2014-01-03 13:32:13 -05:00
app . post ( ' /auth/logout ' , (req, res) ->
req . logout ( )
res . end ( )
)
2014-01-14 17:13:47 -05:00
2014-01-03 13:32:13 -05:00
app . post ( ' /auth/reset ' , (req, res) ->
unless req . body . email
2014-02-02 18:01:40 -05:00
return errors . badInput ( res , [ { message : ' Need an email specified. ' , property : ' email ' } ] )
2014-01-14 17:13:47 -05:00
2014-01-03 13:32:13 -05:00
User . findOne ( { emailLower : req . body . email . toLowerCase ( ) } ) . exec ( (err, user) ->
if not user
2014-01-14 17:13:47 -05:00
return errors . notFound ( res , [ { message : ' not found. ' , property : ' email ' } ] )
2014-03-11 00:30:46 -04:00
2014-01-03 13:32:13 -05:00
user . set ( ' passwordReset ' , Math . random ( ) . toString ( 36 ) . slice ( 2 , 7 ) . toUpperCase ( ) )
user . save (err) =>
2014-01-14 17:13:47 -05:00
return errors . serverError ( res ) if err
2014-01-03 17:28:26 -05:00
if config . isProduction
2014-01-03 13:32:13 -05:00
options = createMailOptions req . body . email , user . get ( ' passwordReset ' )
2014-01-24 14:47:14 -05:00
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 } "
2014-01-14 17:13:47 -05:00
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
2014-05-09 19:33:06 -04:00
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-03-11 00:30:46 -04: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. '
2014-03-11 00:30:46 -04:00
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-01-17 13:47:42 -05:00
User . findOne ( { emailLower : req . query . email . toLowerCase ( ) } ) . exec (err, user) ->
if not user
return errors . notFound res , " No user found with email ' #{ req . query . email } ' "
2014-04-21 19:15:23 -04:00
emails = _ . clone ( user . get ( ' emails ' ) ) or { }
2014-04-22 22:27:39 -04:00
msg = ' '
2014-06-10 19:30:07 -04:00
2014-04-22 22:27:39 -04:00
if req . query . recruitNotes
emails . recruitNotes ? = { }
emails.recruitNotes.enabled = false
msg = " Unsubscribed #{ req . query . email } from recruiting emails. "
2014-06-10 19:30:07 -04:00
2014-04-22 22:27:39 -04:00
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
2014-06-10 19:30:07 -04:00
2014-04-22 22:27:39 -04:00
user . update { $set: { emails: emails } } , { } , =>
2014-01-17 13:47:42 -05:00
return errors . serverError res , ' Database failure. ' if err
2014-04-22 22:27:39 -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
2014-04-02 16:12:24 -04:00
module.exports.loginUser = loginUser = (req, res, user, send=true, next=null) ->
user . save ( (err) ->
if err
return @ sendDatabaseError ( res , err )
req . logIn ( user , (err) ->
if err
return @ sendDatabaseError ( res , err )
if send
return @ sendSuccess ( res , user )
next ( ) if next
)
)
module.exports.makeNewUser = makeNewUser = (req) ->
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-06-10 19:30:07 -04:00
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
subject: " [CodeCombat] Password Reset "
text: " You can log into your account with: #{ password } "