freeCodeCamp/app.js

345 lines
8.9 KiB
JavaScript
Raw Normal View History

require('newrelic');
require('dotenv').load();
2014-01-07 00:31:30 +00:00
/**
* Module dependencies.
*/
var express = require('express'),
debug = require('debug')('freecc:server'),
cookieParser = require('cookie-parser'),
compress = require('compression'),
session = require('express-session'),
logger = require('morgan'),
errorHandler = require('errorhandler'),
methodOverride = require('method-override'),
bodyParser = require('body-parser'),
helmet = require('helmet'),
_ = require('lodash'),
MongoStore = require('connect-mongo')(session),
flash = require('express-flash'),
path = require('path'),
mongoose = require('mongoose'),
passport = require('passport'),
expressValidator = require('express-validator'),
connectAssets = require('connect-assets'),
/**
* Controllers (route handlers).
*/
homeController = require('./controllers/home'),
challengesController = require('./controllers/challenges'),
resourcesController = require('./controllers/resources'),
userController = require('./controllers/user'),
contactController = require('./controllers/contact'),
/**
* User model
*/
User = require('./models/User'),
/**
* API keys and Passport configuration.
*/
secrets = require('./config/secrets'),
passportConf = require('./config/passport');
2013-11-27 04:15:13 +00:00
/**
* Create Express server.
*/
var app = express();
/**
* Connect to MongoDB.
*/
2014-02-26 03:39:28 +00:00
mongoose.connect(secrets.db);
mongoose.connection.on('error', function() {
console.error(
'MongoDB Connection Error. Please make sure that MongoDB is running.'
);
});
2013-11-13 17:32:22 +00:00
2014-05-06 04:44:30 +00:00
/**
* Express configuration.
*/
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(compress());
2014-02-21 22:29:06 +00:00
app.use(connectAssets({
paths: [
path.join(__dirname, 'public/css'),
path.join(__dirname, 'public/js')
],
2014-10-18 02:23:53 +00:00
helperContext: app.locals
}));
app.use(logger('dev'));
app.use(bodyParser.json());
2014-07-02 05:12:11 +00:00
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator({
customValidators: {
matchRegex: function(param, regex) {
return regex.test(param);
}
}
}));
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,
'auto_reconnect': true
2014-10-18 02:23:53 +00:00
})
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.disable('x-powered-by');
app.use(helmet.xssFilter());
app.use(helmet.xframe());
2014-12-22 20:36:45 +00:00
var trusted = [
2014-12-23 21:30:20 +00:00
"'self'",
2014-12-22 20:36:45 +00:00
'*.freecodecamp.com',
'*.gstatic.com',
2014-12-22 20:36:45 +00:00
"*.google-analytics.com",
"*.googleapis.com",
"*.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
];
debug(trusted);
app.use(helmet.contentSecurityPolicy({
2014-12-22 20:36:45 +00:00
defaultSrc: trusted,
scriptSrc: ['*.optimizely.com'].concat(trusted),
'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,
imgSrc: [
'*.evernote.com',
'*.amazonaws.com',
'data:',
'*.licdn.com',
'*.gravatar.com',
'*.youtube.com'
].concat(trusted),
fontSrc: ['*.googleapis.com'].concat(trusted),
mediaSrc: [
'*.amazonaws.com',
'*.twitter.com'
],
frameSrc: [
'*.gitter.im',
'*.vimeo.com',
'*.twitter.com',
'*.rafflecopter.com'
],
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
}));
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();
});
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();
});
app.use(
express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 })
);
/**
* Main routes.
*/
app.get('/', homeController.index);
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);
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);
app.get('/deploy-a-website', resourcesController.deployAWebsite);
app.get('/gmail-shortcuts', resourcesController.gmailShortcuts);
app.get('/control-shortcuts', resourcesController.controlShortcuts);
app.get('/control-shortcuts', resourcesController.deployAWebsite);
app.get('/stats', resourcesController.stats);
app.get(
'/pair-program-with-team-viewer',
resourcesController.pairProgramWithTeamViewer
);
app.get(
'/done-with-first-100-hours',
resourcesController.doneWithFirst100Hours
);
app.get(
'/programmer-interview-questions-app',
resourcesController.programmerInterviewQuestionsApp
);
2014-11-23 21:08:46 +00:00
app.get('/about', resourcesController.about);
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);
// # Protected routes, user must be logged in.
2014-11-19 23:50:57 +00:00
app.post(
'/update-progress',
passportConf.isAuthenticated,
userController.updateProgress
);
2014-11-19 23:50:57 +00:00
app.get(
'/challenges/:challengeNumber',
challengesController.returnChallenge
);
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);
/**
* 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
*
*/
app.post('/completed_challenge', function(req, res) {
req.user.challengesHash[parseInt(req.body.challengeNumber)] =
Math.round(+ new Date() / 1000);
2014-12-06 04:44:42 +00:00
var ch = req.user.challengesHash;
var p = 0;
for (var k in ch) {
if (ch[k] > 0) { p += 1; }
}
2014-12-06 04:44:42 +00:00
req.user.points = p;
req.user.save();
2014-11-07 01:38:47 +00:00
});
/**
* OAuth sign-in routes.
*/
var passportOptions = {
successRedirect: '/',
failureRedirect: '/login'
};
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get(
'/auth/twitter/callback',
passport.authenticate('twitter', {
successRedirect: '/auth/twitter/middle',
failureRedirect: '/login'
})
);
app.get('/auth/twitter/middle', passportConf.hasEmail);
app.get(
'/auth/linkedin',
passport.authenticate('linkedin', {
state: 'SOME STATE'
})
);
app.get(
'/auth/linkedin/callback',
passport.authenticate('linkedin', passportOptions)
);
app.get(
'/auth/facebook',
passport.authenticate('facebook', { scope: ['email', 'user_location'] })
);
app.get(
'/auth/facebook/callback',
passport.authenticate('facebook', passportOptions), function(req, res) {
res.redirect(req.session.returnTo || '/');
}
);
app.get('/auth/github', passport.authenticate('github'));
app.get(
'/auth/github/callback',
passport.authenticate('github', passportOptions), 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', passportOptions), function(req, res) {
res.redirect(req.session.returnTo || '/');
}
);
/**
* 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;