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 '
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) ->
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-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-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-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
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-03-11 00:30:46 -04:00
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-03-11 00:30:46 -04:00
2014-06-30 22:16:26 -04: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) ->
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-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-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 )
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-06-30 22:16:26 -04:00
return errors . badInput ( res , [ { message: ' Need an email specified. ' , property: ' email ' } ] )
2014-01-14 17:13:47 -05:00
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-03-11 00:30:46 -04:00
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) =>
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-07-16 22:46:06 -04:00
app . get ' /auth/unsubscribe ' , (req, res) ->
req.query.email = decodeURIComponent ( req . query . email )
2014-01-17 13:47:42 -05:00
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-07-16 22:46:06 -04:00
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 } ' "
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-07-16 19:37:06 -04:00
else if req . query . employerNotes
emails . employerNotes ? = { }
emails.employerNotes.enabled = false
2014-07-16 22:46:06 -04:00
2014-07-16 19:37:06 -04:00
msg = " Unsubscribed #{ req . query . email } from employer emails. "
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-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
2014-07-14 14:05:03 -04:00
app . get ' /auth/name* ' , (req, res) ->
2014-07-10 14:50:16 -04:00
parts = req . path . split ' / '
2014-07-14 14:05:03 -04:00
originalName = decodeURI parts [ 3 ]
return errors . badInput res , ' No name provided. ' unless parts . length > 3 and originalName ? and originalName isnt ' '
2014-07-10 14:50:16 -04:00
return errors . notFound res if parts . length isnt 4
User . unconflictName originalName , (err, name) ->
return errors . serverError res , err if err
response = name: name
if originalName is name
res . send 200 , response
else
errors . conflict res , response
2014-04-02 16:12:24 -04: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 ?
2014-04-02 16:12:24 -04:00
req . logIn ( user , (err) ->
2014-07-10 04:07:36 -04:00
return errors . serverError res , err if err ?
2014-07-10 14:50:16 -04:00
return res . send ( user ) and res . end ( ) if send
2014-04-02 16:12:24 -04:00
next ( ) if next
)
)
module.exports.makeNewUser = makeNewUser = (req) ->
2014-06-30 22:16:26 -04:00
user = new User ( { anonymous: true } )
2014-04-02 16:12:24 -04:00
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
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 } "