Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging
This commit is contained in:
@ -161,9 +161,9 @@ module.exports = function(User) {
|
||||
if (!username) {
|
||||
// Zalgo!!
|
||||
return nextTick(() => {
|
||||
cb(
|
||||
new TypeError('FCC: username should be a string but got %s', username)
|
||||
);
|
||||
cb(new TypeError(
|
||||
`username should be a string but got ${ username }`
|
||||
));
|
||||
});
|
||||
}
|
||||
User.findOne({ where: { username } }, (err, user) => {
|
||||
@ -171,7 +171,7 @@ module.exports = function(User) {
|
||||
return cb(err);
|
||||
}
|
||||
if (!user || user.username !== username) {
|
||||
return cb(new Error('FCC: no user found for %s', username));
|
||||
return cb(new Error(`no user found for ${ username }`));
|
||||
}
|
||||
const aboutUser = getAboutProfile(user);
|
||||
return cb(null, aboutUser);
|
||||
|
@ -19,28 +19,14 @@
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"facebook": {
|
||||
"type": "string"
|
||||
},
|
||||
"twitter": {
|
||||
"type": "string"
|
||||
},
|
||||
"google": {
|
||||
"type": "string"
|
||||
},
|
||||
"github": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkedin": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "array"
|
||||
},
|
||||
"progressTimestamps": {
|
||||
"type": "array",
|
||||
"default": []
|
||||
},
|
||||
"isGithubCool": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"lowercase": true,
|
||||
@ -123,12 +109,6 @@
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"resetPasswordToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"resetPasswordExpires": {
|
||||
"type": "string"
|
||||
},
|
||||
"completedBonfires": {
|
||||
"type": [
|
||||
{
|
||||
@ -170,21 +150,10 @@
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"needsSomeDataModeled": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"needsMigration": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"sendMonthlyEmail": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"challengesHash": {
|
||||
"type": {}
|
||||
},
|
||||
"currentChallenge": {
|
||||
"type": {}
|
||||
},
|
||||
@ -205,10 +174,6 @@
|
||||
}
|
||||
],
|
||||
"default": []
|
||||
},
|
||||
"uncompletedChallenges": {
|
||||
"type": "array",
|
||||
"default": []
|
||||
}
|
||||
},
|
||||
"validations": [],
|
||||
|
@ -66,7 +66,7 @@
|
||||
"lodash": "^3.9.3",
|
||||
"loopback": "https://github.com/FreeCodeCamp/loopback.git#fix/no-password",
|
||||
"loopback-boot": "^2.8.0",
|
||||
"loopback-component-passport": "1.4.0",
|
||||
"loopback-component-passport": "^1.5.0",
|
||||
"loopback-connector-mongodb": "^1.10.0",
|
||||
"lusca": "~1.0.2",
|
||||
"method-override": "~2.3.0",
|
||||
|
@ -577,6 +577,7 @@ thead {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@
|
||||
"difficulty": "9.98141",
|
||||
"description": [
|
||||
"",
|
||||
"In JavaScript whole numbers (called integers) can be really easily to preform mathematical functions",
|
||||
"In JavaScript whole numbers (called integers) can be easily used to preform mathematical functions",
|
||||
"Let's try a few of the most commonly used ones now",
|
||||
"We use <code> + </code> for addition",
|
||||
"Replace the <code> 0 </code> with correct number to achieve the result in the comment."
|
||||
@ -301,7 +301,7 @@
|
||||
"difficulty": "9.98142",
|
||||
"description": [
|
||||
"",
|
||||
"In JavaScript whole numbers (called integers) can be really easily to preform mathematical functions",
|
||||
"In JavaScript whole numbers (called integers) can be easily used to preform mathematical functions",
|
||||
"Let's try a few of the most commonly used ones now",
|
||||
"We use <code> - </code> for subtraction",
|
||||
"Replace the <code> 0 </code> with correct number to achieve the result in the comment."
|
||||
@ -325,7 +325,7 @@
|
||||
"difficulty": "9.98143",
|
||||
"description": [
|
||||
"",
|
||||
"In JavaScript whole numbers (called integers) can be really easily to preform mathematical functions",
|
||||
"In JavaScript whole numbers (called integers) can be easily used to preform mathematical functions",
|
||||
"Let's try a few of the most commonly used ones now",
|
||||
"We use <code> * </code> for multiplication",
|
||||
"Replace the <code> 0 </code> with correct number to achieve the result in the comment."
|
||||
@ -349,7 +349,7 @@
|
||||
"difficulty": "9.9814",
|
||||
"description": [
|
||||
"",
|
||||
"In JavaScript whole numbers (called integers) can be really easily to preform mathematical functions",
|
||||
"In JavaScript whole numbers (called integers) can be easily used to preform mathematical functions",
|
||||
"Let's try a few of the most commonly used ones now",
|
||||
"We use <code> / </code> for division",
|
||||
"Replace the <code> 0 </code> with correct number to achieve the result in the comment."
|
||||
|
@ -12,7 +12,7 @@
|
||||
"Bootstrap will figure out how wide your screen is and respond by resizing your HTML elements - hence the name <code>Responsive Design</code>.",
|
||||
"With responsive design, there is no need to design a mobile version of your website. It will look good on devices with screens of any width.",
|
||||
"You can add Bootstrap to any app just by including it with <code><link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css'/></code> at the top of your HTML. But we've gone ahead and automatically added it to your Cat Photo App for you.",
|
||||
"To get started, we should nest all of our HTML in a <code>div</code> element with the class \"fluid-container\"."
|
||||
"To get started, we should nest all of our HTML in a <code>div</code> element with the class \"container-fluid\"."
|
||||
],
|
||||
"tests": [
|
||||
"assert($('div').hasClass('container-fluid'), 'Your <code>div</code> element should have the class \"row\"')",
|
||||
@ -1566,7 +1566,7 @@
|
||||
"difficulty": 2.18,
|
||||
"description": [
|
||||
"Now let's make sure all the content on your page is mobile-responsive.",
|
||||
"Let's nest your <code>h3</code> element within a <code>div<code> element with the class \"containter-fluid\"."
|
||||
"Let's nest your <code>h3</code> element within a <code>div<code> element with the class \"container-fluid\"."
|
||||
],
|
||||
"tests": [
|
||||
"assert($('div').hasClass('container-fluid'), 'Your <code>div</code> element should have the class \"container-fluid\"')",
|
||||
@ -1743,7 +1743,7 @@
|
||||
],
|
||||
"tests": [
|
||||
"assert($('.btn').length > 5, 'Apply the \"btn\" class to each of your <code>button</code> elements.')",
|
||||
"assert($('.btn').length > 5, 'Apply the \"btn-default\" class to each of your <code>button</code> elements.')"
|
||||
"assert($('.btn-default').length > 5, 'Apply the \"btn-default\" class to each of your <code>button</code> elements.')"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"<div class='container-fluid'>",
|
||||
|
@ -1,27 +1,60 @@
|
||||
{
|
||||
"initial:before": {
|
||||
"loopback#favicon": {}
|
||||
"loopback#favicon": {
|
||||
"params": "$!../public/favicon.ico"
|
||||
}
|
||||
},
|
||||
"initial": {
|
||||
"compression": {}
|
||||
"compression": {},
|
||||
"morgan": {
|
||||
"params": "dev"
|
||||
}
|
||||
},
|
||||
"session": {
|
||||
"./middlewares/sessions.js": {}
|
||||
},
|
||||
"auth:before": {
|
||||
"./middlewares/add-return-to": {}
|
||||
},
|
||||
"auth": {
|
||||
},
|
||||
"parse": {
|
||||
"body-parser#json": {},
|
||||
"body-parser#urlencoded": {
|
||||
"params": { "extended": true }
|
||||
},
|
||||
"method-override": {},
|
||||
"./middlewares/cookie-parser": {}
|
||||
},
|
||||
"parse:after": {
|
||||
"./middlewares/validator": {}
|
||||
},
|
||||
"routes:before": {
|
||||
"express-flash": {},
|
||||
"helmet#xssFilter": {},
|
||||
"helmet#noSniff": {},
|
||||
"helmet#frameguard": {},
|
||||
"./middlewares/constant-headers": {},
|
||||
"./middlewares/csp": {},
|
||||
"./middlewares/express-rx": {},
|
||||
"./middlewares/global-locals": {}
|
||||
},
|
||||
"routes": {
|
||||
},
|
||||
"files": {
|
||||
"loopback#static": {
|
||||
"params": "$!../public"
|
||||
"params": [
|
||||
"$!../public",
|
||||
{
|
||||
"maxAge": "86400000"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"final": {
|
||||
"loopback#urlNotFound": {}
|
||||
},
|
||||
"final:after": {
|
||||
"errorhandler": {}
|
||||
"./middlewares/keymetrics": {},
|
||||
"./middlewares/error-handlers": {}
|
||||
}
|
||||
}
|
||||
|
13
server/middlewares/add-return-to.js
Normal file
13
server/middlewares/add-return-to.js
Normal file
@ -0,0 +1,13 @@
|
||||
export default function addReturnToUrl() {
|
||||
return function(req, res, next) {
|
||||
// Remember original destination before login.
|
||||
var path = req.path.split('/')[1];
|
||||
if (/auth|login|logout|signin|signup|fonts|favicon/i.test(path)) {
|
||||
return next();
|
||||
} else if (/\/stories\/\w+/i.test(req.path)) {
|
||||
return next();
|
||||
}
|
||||
req.session.returnTo = req.path;
|
||||
next();
|
||||
};
|
||||
}
|
9
server/middlewares/constant-headers.js
Normal file
9
server/middlewares/constant-headers.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default function constantHeaders() {
|
||||
return function(req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers',
|
||||
'Origin, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
next();
|
||||
};
|
||||
}
|
4
server/middlewares/cookie-parser.js
Normal file
4
server/middlewares/cookie-parser.js
Normal file
@ -0,0 +1,4 @@
|
||||
import cookieParser from 'cookie-parser';
|
||||
import secrets from '../../config/secrets';
|
||||
|
||||
export default cookieParser.bind(cookieParser, secrets.cookieSecret);
|
98
server/middlewares/csp.js
Normal file
98
server/middlewares/csp.js
Normal file
@ -0,0 +1,98 @@
|
||||
import helmet from 'helmet';
|
||||
|
||||
const trusted = [
|
||||
"'self'",
|
||||
'blob:',
|
||||
'104.236.218.15',
|
||||
'*.freecodecamp.com',
|
||||
'http://www.freecodecamp.com',
|
||||
'https://www.freecodecamp.com',
|
||||
'https://freecodecamp.com',
|
||||
'https://freecodecamp.org',
|
||||
'*.freecodecamp.org',
|
||||
// NOTE(berks): add the following as the blob above was not covering www
|
||||
'http://www.freecodecamp.org',
|
||||
'ws://freecodecamp.com/',
|
||||
'ws://www.freecodecamp.com/',
|
||||
'*.gstatic.com',
|
||||
'*.google-analytics.com',
|
||||
'*.googleapis.com',
|
||||
'*.google.com',
|
||||
'*.gstatic.com',
|
||||
'*.doubleclick.net',
|
||||
'*.twitter.com',
|
||||
'*.twitch.tv',
|
||||
'*.twimg.com',
|
||||
"'unsafe-eval'",
|
||||
"'unsafe-inline'",
|
||||
'*.bootstrapcdn.com',
|
||||
'*.cloudflare.com',
|
||||
'https://*.cloudflare.com',
|
||||
'localhost:3001',
|
||||
'ws://localhost:3001/',
|
||||
'http://localhost:3001',
|
||||
'localhost:3000',
|
||||
'ws://localhost:3000/',
|
||||
'http://localhost:3000',
|
||||
'*.ionicframework.com',
|
||||
'https://syndication.twitter.com',
|
||||
'*.youtube.com',
|
||||
'*.jsdelivr.net',
|
||||
'https://*.jsdelivr.net',
|
||||
'*.ytimg.com',
|
||||
'*.bitly.com',
|
||||
'http://cdn.inspectlet.com/',
|
||||
'https://cdn.inspeclet.com/',
|
||||
'wss://inspectletws.herokuapp.com/',
|
||||
'http://hn.inspectlet.com/',
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com',
|
||||
'https://hn.inspectlet.com/'
|
||||
];
|
||||
|
||||
export default function csp() {
|
||||
return helmet.csp({
|
||||
defaultSrc: trusted,
|
||||
scriptSrc: [
|
||||
'*.optimizely.com',
|
||||
'*.aspnetcdn.com',
|
||||
'*.d3js.org',
|
||||
'https://cdn.inspectlet.com/inspectlet.js',
|
||||
'http://cdn.inspectlet.com/inspectlet.js',
|
||||
'http://beta.freecodecamp.com'
|
||||
].concat(trusted),
|
||||
'connect-src': [
|
||||
'vimeo.com'
|
||||
].concat(trusted),
|
||||
styleSrc: [
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com'
|
||||
].concat(trusted),
|
||||
imgSrc: [
|
||||
// allow all input since we have user submitted images for
|
||||
// public profile
|
||||
'*'
|
||||
].concat(trusted),
|
||||
fontSrc: [
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com'
|
||||
].concat(trusted),
|
||||
mediaSrc: [
|
||||
'*.amazonaws.com',
|
||||
'*.twitter.com'
|
||||
].concat(trusted),
|
||||
frameSrc: [
|
||||
'*.gitter.im',
|
||||
'*.gitter.im https:',
|
||||
'*.vimeo.com',
|
||||
'*.twitter.com',
|
||||
'*.ghbtns.com'
|
||||
].concat(trusted),
|
||||
// set to true if you only want to report errors
|
||||
reportOnly: false,
|
||||
// set to true if you want to set all headers
|
||||
setAllHeaders: false,
|
||||
// set to true if you want to force buggy CSP in Safari 5
|
||||
safari5: false
|
||||
});
|
||||
}
|
43
server/middlewares/error-handlers.js
Normal file
43
server/middlewares/error-handlers.js
Normal file
@ -0,0 +1,43 @@
|
||||
import errorHanlder from 'errorhandler';
|
||||
import accepts from 'accepts';
|
||||
|
||||
export default function prodErrorHandler() {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return errorHanlder({ log: true });
|
||||
}
|
||||
// error handling in production.
|
||||
// disabling eslint due to express parity rules for error handlers
|
||||
return function(err, req, res, next) { // eslint-disable-line
|
||||
// respect err.status
|
||||
if (err.status) {
|
||||
res.statusCode = err.status;
|
||||
}
|
||||
|
||||
// default status code to 500
|
||||
if (res.statusCode < 400) {
|
||||
res.statusCode = 500;
|
||||
}
|
||||
|
||||
// parse res type
|
||||
var accept = accepts(req);
|
||||
var type = accept.type('html', 'json', 'text');
|
||||
|
||||
var message = 'opps! Something went wrong. Please try again later';
|
||||
if (type === 'html') {
|
||||
req.flash('errors', {
|
||||
msg: message
|
||||
});
|
||||
return res.redirect('/');
|
||||
// json
|
||||
} else if (type === 'json') {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
return res.send({
|
||||
message: message
|
||||
});
|
||||
// plain text
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
return res.send(message);
|
||||
}
|
||||
};
|
||||
}
|
10
server/middlewares/express-rx.js
Normal file
10
server/middlewares/express-rx.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { Observable } from 'rx';
|
||||
|
||||
// add rx methods to express
|
||||
export default function expressRx() {
|
||||
return function expressRx(req, res, next) {
|
||||
// render to observable stream
|
||||
res.render$ = Observable.fromNodeCallback(res.render, res);
|
||||
next();
|
||||
};
|
||||
}
|
7
server/middlewares/global-locals.js
Normal file
7
server/middlewares/global-locals.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default function globalLocals() {
|
||||
return function(req, res, next) {
|
||||
// Make user object available in templates.
|
||||
res.locals.user = req.user;
|
||||
next();
|
||||
};
|
||||
}
|
8
server/middlewares/keymetrics.js
Normal file
8
server/middlewares/keymetrics.js
Normal file
@ -0,0 +1,8 @@
|
||||
import pmx from 'pmx';
|
||||
|
||||
export default function keymetrics() {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return (err, req, res, next) => next(err);
|
||||
}
|
||||
return pmx.expressErrorHandler();
|
||||
}
|
17
server/middlewares/sessions.js
Normal file
17
server/middlewares/sessions.js
Normal file
@ -0,0 +1,17 @@
|
||||
import session from 'express-session';
|
||||
import MongoStoreFactory from 'connect-mongo';
|
||||
import secrets from '../../config/secrets';
|
||||
|
||||
const MongoStore = MongoStoreFactory(session);
|
||||
|
||||
export default function sessionsMiddleware() {
|
||||
return session({
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
secret: secrets.sessionSecret,
|
||||
store: new MongoStore({
|
||||
url: secrets.db,
|
||||
'autoReconnect': true
|
||||
})
|
||||
});
|
||||
}
|
9
server/middlewares/validator.js
Normal file
9
server/middlewares/validator.js
Normal file
@ -0,0 +1,9 @@
|
||||
import validator from 'express-validator';
|
||||
|
||||
export default validator.bind(validator, {
|
||||
customValidators: {
|
||||
matchRegex: function matchRegex(param, regex) {
|
||||
return regex.test(param);
|
||||
}
|
||||
}
|
||||
});
|
238
server/server.js
238
server/server.js
@ -5,28 +5,9 @@ pmx.init();
|
||||
var assign = require('lodash').assign,
|
||||
loopback = require('loopback'),
|
||||
boot = require('loopback-boot'),
|
||||
accepts = require('accepts'),
|
||||
cookieParser = require('cookie-parser'),
|
||||
compress = require('compression'),
|
||||
session = require('express-session'),
|
||||
expressState = require('express-state'),
|
||||
logger = require('morgan'),
|
||||
errorHandler = require('errorhandler'),
|
||||
methodOverride = require('method-override'),
|
||||
bodyParser = require('body-parser'),
|
||||
helmet = require('helmet'),
|
||||
MongoStore = require('connect-mongo')(session),
|
||||
flash = require('express-flash'),
|
||||
path = require('path'),
|
||||
expressValidator = require('express-validator'),
|
||||
lessMiddleware = require('less-middleware'),
|
||||
|
||||
passportProviders = require('./passport-providers'),
|
||||
rxMiddleware = require('./utils/rx').rxMiddleware,
|
||||
/**
|
||||
* API keys and Passport configuration.
|
||||
*/
|
||||
secrets = require('./../config/secrets');
|
||||
passportProviders = require('./passport-providers');
|
||||
|
||||
var generateKey =
|
||||
require('loopback-component-passport/lib/models/utils').generateKey;
|
||||
@ -45,176 +26,16 @@ var passportConfigurator = new PassportConfigurator(app);
|
||||
app.set('port', process.env.PORT || 3000);
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
app.use(compress());
|
||||
app.use(lessMiddleware(path.join(__dirname, '/public')));
|
||||
app.use(logger('dev'));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: true
|
||||
}));
|
||||
app.use(expressValidator({
|
||||
customValidators: {
|
||||
matchRegex: function(param, regex) {
|
||||
return regex.test(param);
|
||||
}
|
||||
}
|
||||
}));
|
||||
app.use(methodOverride());
|
||||
app.use(cookieParser(secrets.cookieSecret));
|
||||
app.use(session({
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
secret: secrets.sessionSecret,
|
||||
store: new MongoStore({
|
||||
url: secrets.db,
|
||||
'autoReconnect': true
|
||||
})
|
||||
}));
|
||||
|
||||
app.use(flash());
|
||||
app.disable('x-powered-by');
|
||||
|
||||
app.use(helmet.xssFilter());
|
||||
app.use(helmet.noSniff());
|
||||
app.use(helmet.frameguard());
|
||||
app.use(function(req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers',
|
||||
'Origin, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
next();
|
||||
});
|
||||
|
||||
var trusted = [
|
||||
"'self'",
|
||||
'blob:',
|
||||
'104.236.218.15',
|
||||
'*.freecodecamp.com',
|
||||
'http://www.freecodecamp.com',
|
||||
'https://www.freecodecamp.com',
|
||||
'https://freecodecamp.com',
|
||||
'https://freecodecamp.org',
|
||||
'*.freecodecamp.org',
|
||||
// NOTE(berks): add the following as the blob above was not covering www
|
||||
'http://www.freecodecamp.org',
|
||||
'ws://freecodecamp.com/',
|
||||
'ws://www.freecodecamp.com/',
|
||||
'*.gstatic.com',
|
||||
'*.google-analytics.com',
|
||||
'*.googleapis.com',
|
||||
'*.google.com',
|
||||
'*.gstatic.com',
|
||||
'*.doubleclick.net',
|
||||
'*.twitter.com',
|
||||
'*.twitch.tv',
|
||||
'*.twimg.com',
|
||||
"'unsafe-eval'",
|
||||
"'unsafe-inline'",
|
||||
'*.bootstrapcdn.com',
|
||||
'*.cloudflare.com',
|
||||
'https://*.cloudflare.com',
|
||||
'localhost:3001',
|
||||
'ws://localhost:3001/',
|
||||
'http://localhost:3001',
|
||||
'localhost:3000',
|
||||
'ws://localhost:3000/',
|
||||
'http://localhost:3000',
|
||||
'*.ionicframework.com',
|
||||
'https://syndication.twitter.com',
|
||||
'*.youtube.com',
|
||||
'*.jsdelivr.net',
|
||||
'https://*.jsdelivr.net',
|
||||
'*.ytimg.com',
|
||||
'*.bitly.com',
|
||||
'http://cdn.inspectlet.com/',
|
||||
'https://cdn.inspeclet.com/',
|
||||
'wss://inspectletws.herokuapp.com/',
|
||||
'http://hn.inspectlet.com/',
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com',
|
||||
'https://hn.inspectlet.com/'
|
||||
];
|
||||
|
||||
app.use(helmet.csp({
|
||||
defaultSrc: trusted,
|
||||
scriptSrc: [
|
||||
'*.optimizely.com',
|
||||
'*.aspnetcdn.com',
|
||||
'*.d3js.org',
|
||||
'https://cdn.inspectlet.com/inspectlet.js',
|
||||
'http://cdn.inspectlet.com/inspectlet.js',
|
||||
'http://beta.freecodecamp.com'
|
||||
].concat(trusted),
|
||||
'connect-src': [
|
||||
'vimeo.com'
|
||||
].concat(trusted),
|
||||
styleSrc: [
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com'
|
||||
].concat(trusted),
|
||||
imgSrc: [
|
||||
/* allow all input since we have user submitted images for public profile*/
|
||||
'*'
|
||||
].concat(trusted),
|
||||
fontSrc: [
|
||||
'*.googleapis.com',
|
||||
'*.gstatic.com'
|
||||
].concat(trusted),
|
||||
mediaSrc: [
|
||||
'*.amazonaws.com',
|
||||
'*.twitter.com'
|
||||
].concat(trusted),
|
||||
frameSrc: [
|
||||
'*.gitter.im',
|
||||
'*.gitter.im https:',
|
||||
'*.vimeo.com',
|
||||
'*.twitter.com',
|
||||
'*.ghbtns.com'
|
||||
].concat(trusted),
|
||||
// set to true if you only want to report errors
|
||||
reportOnly: false,
|
||||
// set to true if you want to set all headers
|
||||
setAllHeaders: false,
|
||||
// set to true if you want to force buggy CSP in Safari 5
|
||||
safari5: false
|
||||
}));
|
||||
|
||||
// adds passport initialization after session middleware phase is complete
|
||||
passportConfigurator.init();
|
||||
|
||||
// add rx methods to express
|
||||
app.use(rxMiddleware());
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
|
||||
// Make user object available in templates.
|
||||
res.locals.user = req.user;
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.use(
|
||||
loopback.static(path.join(__dirname, '../public'), {
|
||||
maxAge: 86400000
|
||||
})
|
||||
);
|
||||
|
||||
boot(app, {
|
||||
appRootDir: __dirname,
|
||||
dev: process.env.NODE_ENV
|
||||
});
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
// Remember original destination before login.
|
||||
var path = req.path.split('/')[1];
|
||||
if (/auth|login|logout|signin|signup|fonts|favicon/i.test(path)) {
|
||||
return next();
|
||||
} else if (/\/stories\/\w+/i.test(req.path)) {
|
||||
return next();
|
||||
}
|
||||
req.session.returnTo = req.path;
|
||||
next();
|
||||
});
|
||||
|
||||
passportConfigurator.setupModels({
|
||||
userModel: app.models.user,
|
||||
@ -244,6 +65,9 @@ var passportOptions = {
|
||||
if (email) {
|
||||
userObj.email = email;
|
||||
}
|
||||
if (provider === 'github-login') {
|
||||
userObj.isGithubCool = true;
|
||||
}
|
||||
return userObj;
|
||||
}
|
||||
};
|
||||
@ -257,58 +81,6 @@ Object.keys(passportProviders).map(function(strategy) {
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* OAuth sign-in routes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 500 Error Handler.
|
||||
*/
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
app.use(errorHandler({
|
||||
log: true
|
||||
}));
|
||||
} else {
|
||||
app.use(pmx.expressErrorHandler());
|
||||
// error handling in production disabling eslint due to express parity rules
|
||||
// for error handlers
|
||||
app.use(function(err, req, res, next) { // eslint-disable-line
|
||||
|
||||
// respect err.status
|
||||
if (err.status) {
|
||||
res.statusCode = err.status;
|
||||
}
|
||||
|
||||
// default status code to 500
|
||||
if (res.statusCode < 400) {
|
||||
res.statusCode = 500;
|
||||
}
|
||||
|
||||
// parse res type
|
||||
var accept = accepts(req);
|
||||
var type = accept.type('html', 'json', 'text');
|
||||
|
||||
var message = 'opps! Something went wrong. Please try again later';
|
||||
if (type === 'html') {
|
||||
req.flash('errors', {
|
||||
msg: message
|
||||
});
|
||||
return res.redirect('/');
|
||||
// json
|
||||
} else if (type === 'json') {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
return res.send({
|
||||
message: message
|
||||
});
|
||||
// plain text
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
return res.send(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.start = function() {
|
||||
app.listen(app.get('port'), function() {
|
||||
app.emit('started');
|
||||
|
@ -30,12 +30,3 @@ exports.observableQueryFromModel =
|
||||
exports.observeMethod = function observeMethod(context, methodName) {
|
||||
return Rx.Observable.fromNodeCallback(context[methodName], context);
|
||||
};
|
||||
|
||||
// add rx methods to express
|
||||
exports.rxMiddleware = function rxMiddleware() {
|
||||
return function rxMiddleware(req, res, next) {
|
||||
// render to observable
|
||||
res.render$ = Rx.Observable.fromNodeCallback(res.render, res);
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
@ -268,7 +268,7 @@ block content
|
||||
| Link GitHub with my account
|
||||
if (!user.twitter)
|
||||
.col-xs-12
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/auth/twitter')
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social.disabled(href='#')
|
||||
i.fa.fa-twitter
|
||||
| Link Twitter with my account
|
||||
if (!user.google)
|
||||
|
@ -2,7 +2,7 @@ extends ../layout
|
||||
block content
|
||||
.jumbotron.text-center
|
||||
h2 Sign in with one of these options:
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-social(href='/auth/github')
|
||||
a.btn.btn-lg.btn-block.btn-github.btn-social(href='/auth/github')
|
||||
i.fa.fa-github
|
||||
| Sign in with Github
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-social(href='/auth/twitter')
|
||||
|
@ -1,5 +1,8 @@
|
||||
extends layout
|
||||
block content
|
||||
.bg-danger
|
||||
a(href='https://github.com/FreeCodeCamp/freecodecamp/wiki/beta before continuing')
|
||||
h3 Warning! You are on beta! Please read this link before continuing! https://github.com/freecodecamp/freecodecamp/wiki/beta
|
||||
.jumbotron
|
||||
.text-center
|
||||
h1.hug-top Code with Us
|
||||
|
Reference in New Issue
Block a user