2014-01-07 00:31:30 +00:00
|
|
|
/**
|
|
|
|
* Module dependencies.
|
|
|
|
*/
|
2014-12-22 22:33:25 +00:00
|
|
|
require('newrelic');
|
2014-12-23 00:16:10 +00:00
|
|
|
require('dotenv').load();
|
2013-11-30 05:28:30 +00:00
|
|
|
var express = require('express');
|
2014-12-22 21:38:48 +00:00
|
|
|
var debug = require('debug')('freecc:server');
|
2014-04-12 16:43:07 +00:00
|
|
|
var cookieParser = require('cookie-parser');
|
|
|
|
var compress = require('compression');
|
|
|
|
var session = require('express-session');
|
|
|
|
var bodyParser = require('body-parser');
|
|
|
|
var logger = require('morgan');
|
|
|
|
var errorHandler = require('errorhandler');
|
|
|
|
var methodOverride = require('method-override');
|
2014-11-19 23:30:36 +00:00
|
|
|
var bodyParser = require('body-parser');
|
2014-12-11 04:44:33 +00:00
|
|
|
var helmet = require('helmet');
|
2014-04-12 16:43:07 +00:00
|
|
|
|
2014-06-06 19:57:04 +00:00
|
|
|
var _ = require('lodash');
|
2014-10-18 22:27:08 +00:00
|
|
|
var MongoStore = require('connect-mongo')(session);
|
2014-01-28 19:02:45 +00:00
|
|
|
var flash = require('express-flash');
|
2013-12-20 01:17:15 +00:00
|
|
|
var path = require('path');
|
2013-11-30 05:28:30 +00:00
|
|
|
var mongoose = require('mongoose');
|
|
|
|
var passport = require('passport');
|
2014-01-24 03:18:35 +00:00
|
|
|
var expressValidator = require('express-validator');
|
2014-02-21 22:29:06 +00:00
|
|
|
var connectAssets = require('connect-assets');
|
2014-01-24 03:18:35 +00:00
|
|
|
|
2014-01-07 00:31:30 +00:00
|
|
|
/**
|
2014-06-06 18:58:30 +00:00
|
|
|
* Controllers (route handlers).
|
2014-01-07 00:31:30 +00:00
|
|
|
*/
|
2014-01-12 03:53:31 +00:00
|
|
|
|
2014-01-07 00:22:28 +00:00
|
|
|
var homeController = require('./controllers/home');
|
2014-11-19 23:30:36 +00:00
|
|
|
var challengesController = require('./controllers/challenges');
|
|
|
|
var resourcesController = require('./controllers/resources');
|
2014-01-07 00:22:28 +00:00
|
|
|
var userController = require('./controllers/user');
|
|
|
|
var apiController = require('./controllers/api');
|
|
|
|
var contactController = require('./controllers/contact');
|
2013-11-14 07:29:55 +00:00
|
|
|
|
2014-11-25 19:17:07 +00:00
|
|
|
/**
|
|
|
|
* User model
|
|
|
|
*/
|
|
|
|
var User = require('./models/User');
|
2014-01-07 00:31:30 +00:00
|
|
|
/**
|
2014-06-06 18:58:30 +00:00
|
|
|
* API keys and Passport configuration.
|
2014-01-07 00:31:30 +00:00
|
|
|
*/
|
2014-01-12 03:53:31 +00:00
|
|
|
|
2013-12-20 06:31:16 +00:00
|
|
|
var secrets = require('./config/secrets');
|
2013-11-27 04:15:13 +00:00
|
|
|
var passportConf = require('./config/passport');
|
|
|
|
|
2014-02-02 10:38:38 +00:00
|
|
|
/**
|
|
|
|
* Create Express server.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var app = express();
|
|
|
|
|
2014-01-12 03:53:31 +00:00
|
|
|
/**
|
2014-06-06 18:58:30 +00:00
|
|
|
* Connect to MongoDB.
|
2014-01-12 03:53:31 +00:00
|
|
|
*/
|
2014-01-13 09:24:31 +00:00
|
|
|
|
2014-02-26 03:39:28 +00:00
|
|
|
mongoose.connect(secrets.db);
|
2014-01-12 03:53:31 +00:00
|
|
|
mongoose.connection.on('error', function() {
|
2014-11-09 04:42:48 +00:00
|
|
|
console.error('MongoDB Connection Error. Please make sure that MongoDB is running.');
|
2014-01-12 03:53:31 +00:00
|
|
|
});
|
2013-11-13 17:32:22 +00:00
|
|
|
|
2014-05-06 04:44:30 +00:00
|
|
|
/**
|
|
|
|
* Express configuration.
|
|
|
|
*/
|
2014-04-18 18:29:30 +00:00
|
|
|
|
2014-01-12 03:53:31 +00:00
|
|
|
app.set('port', process.env.PORT || 3000);
|
|
|
|
app.set('views', path.join(__dirname, 'views'));
|
|
|
|
app.set('view engine', 'jade');
|
2014-06-06 18:58:30 +00:00
|
|
|
app.use(compress());
|
2014-02-21 22:29:06 +00:00
|
|
|
app.use(connectAssets({
|
2014-10-18 02:23:53 +00:00
|
|
|
paths: [path.join(__dirname, 'public/css'), path.join(__dirname, 'public/js')],
|
|
|
|
helperContext: app.locals
|
2014-02-03 13:34:12 +00:00
|
|
|
}));
|
2014-04-12 16:43:07 +00:00
|
|
|
app.use(logger('dev'));
|
|
|
|
app.use(bodyParser.json());
|
2014-07-02 05:12:11 +00:00
|
|
|
app.use(bodyParser.urlencoded({ extended: true }));
|
2014-01-24 03:18:35 +00:00
|
|
|
app.use(expressValidator());
|
2014-04-12 16:43:07 +00:00
|
|
|
app.use(methodOverride());
|
|
|
|
app.use(cookieParser());
|
|
|
|
app.use(session({
|
2014-10-18 02:23:53 +00:00
|
|
|
resave: true,
|
|
|
|
saveUninitialized: true,
|
|
|
|
secret: secrets.sessionSecret,
|
|
|
|
store: new MongoStore({
|
|
|
|
url: secrets.db,
|
2014-11-19 23:30:36 +00:00
|
|
|
'auto_reconnect': true
|
2014-10-18 02:23:53 +00:00
|
|
|
})
|
2014-01-29 05:49:09 +00:00
|
|
|
}));
|
2014-01-12 03:53:31 +00:00
|
|
|
app.use(passport.initialize());
|
|
|
|
app.use(passport.session());
|
2014-06-01 15:52:28 +00:00
|
|
|
app.use(flash());
|
2014-12-11 04:44:33 +00:00
|
|
|
app.disable('x-powered-by');
|
|
|
|
app.use(helmet.xssFilter());
|
|
|
|
app.use(helmet.xframe());
|
2014-12-22 20:36:45 +00:00
|
|
|
var trusted = [
|
|
|
|
"'self'",
|
|
|
|
'*.freecodecamp.com',
|
|
|
|
"*.google-analytics.com",
|
|
|
|
"*.googleapis.com",
|
2014-12-23 00:16:10 +00:00
|
|
|
"*.google.com",
|
2014-12-22 20:36:45 +00:00
|
|
|
"*.gstatic.com",
|
|
|
|
"*.doubleclick.net",
|
|
|
|
"*.twitter.com",
|
|
|
|
'*.twimg.com',
|
|
|
|
"*.githubusercontent.com",
|
|
|
|
"'unsafe-eval'",
|
2014-12-22 23:07:32 +00:00
|
|
|
"'unsafe-inline'",
|
2014-12-23 00:47:02 +00:00
|
|
|
"*.rafflecopter.com",
|
|
|
|
"localhost:3001"
|
2014-12-22 20:36:45 +00:00
|
|
|
];
|
2014-12-22 21:38:48 +00:00
|
|
|
//var connectSrc;
|
|
|
|
//if (process.env.NODE_ENV === 'development') {
|
|
|
|
// debug('Pushing');
|
|
|
|
// connectSrc = ['"self"', 'ws://localhost:3001/'];
|
|
|
|
//} else {
|
|
|
|
// debug('Not');
|
|
|
|
// connectSrc = [];
|
|
|
|
//}
|
|
|
|
|
|
|
|
debug(trusted);
|
2014-12-11 04:44:33 +00:00
|
|
|
app.use(helmet.contentSecurityPolicy({
|
2014-12-22 20:36:45 +00:00
|
|
|
defaultSrc: trusted,
|
|
|
|
scriptSrc: ['*.optimizely.com'].concat(trusted),
|
2014-12-23 00:47:02 +00:00
|
|
|
'connect-src': ["ws://*.rafflecopter.com", "wss://*.rafflecopter.com","https://*.rafflecopter.com", "ws://www.freecodecamp.com", 'ws://localhost:3001/', 'http://localhost:3001', 'http://www.freecodecamp.com'],
|
2014-12-22 20:36:45 +00:00
|
|
|
styleSrc: trusted,
|
2014-12-23 00:16:10 +00:00
|
|
|
imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com', '*.gravatar.com', '*.youtube.com'].concat(trusted),
|
2014-12-22 20:36:45 +00:00
|
|
|
fontSrc: ["'self", '*.googleapis.com'].concat(trusted),
|
2014-12-22 21:38:48 +00:00
|
|
|
mediaSrc: ['*.amazonaws.com', '*.twitter.com'],
|
2014-12-23 00:16:10 +00:00
|
|
|
frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com', '*.rafflecopter.com'],
|
2014-12-11 04:44:33 +00:00
|
|
|
// sandbox: ['allow-forms', 'allow-scripts'],
|
|
|
|
// reportUri: '/report-violation',
|
|
|
|
reportOnly: false, // set to true if you only want to report errors
|
|
|
|
setAllHeaders: false, // set to true if you want to set all headers
|
|
|
|
safari5: false // set to true if you want to force buggy CSP in Safari 5
|
|
|
|
}));
|
2014-11-19 23:30:36 +00:00
|
|
|
|
2014-01-12 03:53:31 +00:00
|
|
|
app.use(function(req, res, next) {
|
2014-10-18 02:23:53 +00:00
|
|
|
// Make user object available in templates.
|
|
|
|
res.locals.user = req.user;
|
|
|
|
next();
|
2014-01-12 03:53:31 +00:00
|
|
|
});
|
2014-11-19 23:30:36 +00:00
|
|
|
|
2014-03-08 19:58:27 +00:00
|
|
|
app.use(function(req, res, next) {
|
2014-10-18 02:23:53 +00:00
|
|
|
// Remember original destination before login.
|
|
|
|
var path = req.path.split('/')[1];
|
|
|
|
if (/auth|login|logout|signup|fonts|favicon/i.test(path)) {
|
|
|
|
return next();
|
|
|
|
}
|
|
|
|
req.session.returnTo = req.path;
|
|
|
|
next();
|
2014-03-08 19:58:27 +00:00
|
|
|
});
|
2014-11-19 23:30:36 +00:00
|
|
|
|
2014-10-28 02:38:52 +00:00
|
|
|
app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));
|
2014-01-08 06:37:40 +00:00
|
|
|
|
2014-01-12 03:53:31 +00:00
|
|
|
/**
|
2014-06-06 19:23:28 +00:00
|
|
|
* Main routes.
|
2014-01-12 03:53:31 +00:00
|
|
|
*/
|
2014-06-06 19:23:28 +00:00
|
|
|
app.get('/', homeController.index);
|
2014-11-19 23:30:36 +00:00
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/resources/interview-questions',
|
|
|
|
resourcesController.interviewQuestions);
|
2014-11-12 01:52:03 +00:00
|
|
|
app.get('/learn-to-code', resourcesController.learnToCode);
|
2014-11-30 07:01:49 +00:00
|
|
|
app.get('/privacy', resourcesController.privacy);
|
2014-11-29 23:16:47 +00:00
|
|
|
app.get('/jquery-exercises', resourcesController.jqueryExercises);
|
2014-12-15 06:24:54 +00:00
|
|
|
app.get('/live-pair-programming', resourcesController.livePairProgramming);
|
|
|
|
app.get('/javascript-in-your-inbox', resourcesController.javaScriptInYourInbox);
|
2014-12-12 05:24:44 +00:00
|
|
|
app.get('/chromebook', resourcesController.chromebook);
|
2014-12-16 05:10:13 +00:00
|
|
|
app.get('/pair-program-with-team-viewer', resourcesController.pairProgramWithTeamViewer);
|
2014-12-16 18:31:19 +00:00
|
|
|
app.get('/done-with-first-100-hours', resourcesController.doneWithFirst100Hours);
|
2014-12-10 06:30:18 +00:00
|
|
|
app.get('/programmer-interview-questions-app', resourcesController.programmerInterviewQuestionsApp);
|
2014-12-16 18:31:19 +00:00
|
|
|
|
2014-11-23 21:08:46 +00:00
|
|
|
app.get('/about', resourcesController.about);
|
2014-06-06 19:23:28 +00:00
|
|
|
app.get('/login', userController.getLogin);
|
|
|
|
app.post('/login', userController.postLogin);
|
|
|
|
app.get('/logout', userController.logout);
|
|
|
|
app.get('/forgot', userController.getForgot);
|
|
|
|
app.post('/forgot', userController.postForgot);
|
|
|
|
app.get('/reset/:token', userController.getReset);
|
|
|
|
app.post('/reset/:token', userController.postReset);
|
2014-12-08 00:25:43 +00:00
|
|
|
app.get('/email-signup', userController.getEmailSignup);
|
|
|
|
app.get('/email-signin', userController.getEmailSignin);
|
|
|
|
app.post('/email-signup', userController.postEmailSignup);
|
|
|
|
app.post('/email-signin', userController.postLogin);
|
2014-10-26 16:32:57 +00:00
|
|
|
app.get('/nonprofits', contactController.getContact);
|
|
|
|
app.post('/nonprofits', contactController.postContact);
|
2014-11-19 23:30:36 +00:00
|
|
|
|
|
|
|
// # Protected routes, user must be logged in.
|
2014-11-19 23:50:57 +00:00
|
|
|
app.post(
|
|
|
|
'/update-progress',
|
|
|
|
passportConf.isAuthenticated,
|
|
|
|
userController.updateProgress);
|
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/challenges/:challengeNumber',
|
|
|
|
challengesController.returnChallenge);
|
2014-11-19 23:30:36 +00:00
|
|
|
app.all('/account', passportConf.isAuthenticated);
|
|
|
|
app.get('/account', userController.getAccount);
|
|
|
|
app.post('/account/profile', userController.postUpdateProfile);
|
|
|
|
app.post('/account/password', userController.postUpdatePassword);
|
|
|
|
app.post('/account/delete', userController.postDeleteAccount);
|
|
|
|
app.get('/account/unlink/:provider', userController.getOauthUnlink);
|
|
|
|
|
2014-06-06 18:58:30 +00:00
|
|
|
/**
|
|
|
|
* API examples routes.
|
2014-12-06 04:44:42 +00:00
|
|
|
* accepts a post request. the challenge id req.body.challengeNumber
|
|
|
|
* and updates user.challengesHash & user.challengesCompleted
|
|
|
|
*
|
2014-06-06 18:58:30 +00:00
|
|
|
*/
|
2014-11-19 23:30:36 +00:00
|
|
|
app.post('/completed_challenge', function(req, res) {
|
2014-12-06 04:44:42 +00:00
|
|
|
req.user.challengesHash[parseInt(req.body.challengeNumber)] = Math.round(+new Date() / 1000);
|
|
|
|
var ch = req.user.challengesHash;
|
|
|
|
var p = 0;
|
|
|
|
for (k in ch) {
|
|
|
|
if (ch[k] > 0) { p += 1}
|
2014-11-27 06:00:28 +00:00
|
|
|
}
|
2014-12-06 04:44:42 +00:00
|
|
|
req.user.points = p;
|
2014-11-27 06:00:28 +00:00
|
|
|
req.user.save();
|
2014-11-07 01:38:47 +00:00
|
|
|
});
|
2014-02-01 08:30:14 +00:00
|
|
|
|
|
|
|
/**
|
2014-06-06 18:58:30 +00:00
|
|
|
* OAuth sign-in routes.
|
2014-02-01 08:30:14 +00:00
|
|
|
*/
|
2014-11-30 06:22:27 +00:00
|
|
|
|
2014-11-19 23:30:36 +00:00
|
|
|
app.get('/auth/twitter', passport.authenticate('twitter'));
|
|
|
|
app.get(
|
|
|
|
'/auth/twitter/callback',
|
|
|
|
passport.authenticate('twitter', {
|
|
|
|
successRedirect: '/',
|
|
|
|
failureRedirect: '/login'
|
|
|
|
}), function(req, res) {
|
|
|
|
res.redirect(req.session.returnTo || '/');
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/auth/linkedin',
|
|
|
|
passport.authenticate('linkedin', {
|
|
|
|
state: 'SOME STATE'
|
|
|
|
}));
|
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/auth/linkedin/callback',
|
|
|
|
passport.authenticate('linkedin', {
|
|
|
|
successRedirect: '/',
|
|
|
|
failureRedirect: '/login'
|
|
|
|
}), function(req, res) {
|
|
|
|
res.redirect(req.session.returnTo || '/');
|
|
|
|
});
|
|
|
|
|
2014-11-30 06:22:27 +00:00
|
|
|
app.get('/auth/facebook', passport.authenticate('facebook', { scope: ['email', 'user_location'] }));
|
|
|
|
app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
|
|
|
res.redirect(req.session.returnTo || '/');
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/auth/github', passport.authenticate('github'));
|
|
|
|
app.get('/auth/github/callback', passport.authenticate('github', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
|
|
|
res.redirect(req.session.returnTo || '/');
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/auth/google', passport.authenticate('google', { scope: 'profile email' }));
|
|
|
|
app.get('/auth/google/callback', passport.authenticate('google', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
|
|
|
res.redirect(req.session.returnTo || '/');
|
|
|
|
});
|
|
|
|
|
2014-11-19 23:30:36 +00:00
|
|
|
/**
|
|
|
|
* 500 Error Handler.
|
|
|
|
*/
|
|
|
|
app.use(errorHandler());
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start Express server.
|
|
|
|
*/
|
|
|
|
app.listen(app.get('port'), function() {
|
|
|
|
console.log(
|
|
|
|
'FreeCodeCamp server listening on port %d in %s mode',
|
|
|
|
app.get('port'),
|
|
|
|
app.get('env')
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = app;
|