Merge branch 'staging' into fix/normalize-flash-type
This commit is contained in:
15
server/boot/a-extend-built-ins.js
Normal file
15
server/boot/a-extend-built-ins.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Observable } from 'rx';
|
||||
|
||||
export default function extendEmail(app) {
|
||||
const { AccessToken, Email } = app.models;
|
||||
Email.send$ = Observable.fromNodeCallback(Email.send, Email);
|
||||
AccessToken.findOne$ = Observable.fromNodeCallback(
|
||||
AccessToken.findOne.bind(AccessToken)
|
||||
);
|
||||
AccessToken.prototype.validate$ = Observable.fromNodeCallback(
|
||||
AccessToken.prototype.validate
|
||||
);
|
||||
AccessToken.prototype.destroy$ = Observable.fromNodeCallback(
|
||||
AccessToken.prototype.destroy
|
||||
);
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
import { Observable } from 'rx';
|
||||
|
||||
export default function extendEmail(app) {
|
||||
const { Email } = app.models;
|
||||
Email.send$ = Observable.fromNodeCallback(Email.send, Email);
|
||||
}
|
@@ -1,4 +1,229 @@
|
||||
import _ from 'lodash';
|
||||
import { Observable } from 'rx';
|
||||
import dedent from 'dedent';
|
||||
// import debugFactory from 'debug';
|
||||
import { isEmail } from 'validator';
|
||||
import { check, validationResult } from 'express-validator/check';
|
||||
|
||||
import { ifUserRedirectTo } from '../utils/middleware';
|
||||
import {
|
||||
wrapHandledError,
|
||||
createValidatorErrorFormatter
|
||||
} from '../utils/create-handled-error.js';
|
||||
|
||||
const isSignUpDisabled = !!process.env.DISABLE_SIGNUP;
|
||||
// const debug = debugFactory('fcc:boot:auth');
|
||||
if (isSignUpDisabled) {
|
||||
console.log('fcc:boot:auth - Sign up is disabled');
|
||||
}
|
||||
|
||||
module.exports = function enableAuthentication(app) {
|
||||
// enable authentication
|
||||
// enable loopback access control authentication. see:
|
||||
// loopback.io/doc/en/lb2/Authentication-authorization-and-permissions.html
|
||||
app.enableAuth();
|
||||
const ifUserRedirect = ifUserRedirectTo();
|
||||
const router = app.loopback.Router();
|
||||
const api = app.loopback.Router();
|
||||
const { AuthToken, User } = app.models;
|
||||
|
||||
router.get('/login', (req, res) => res.redirect(301, '/signin'));
|
||||
router.get('/logout', (req, res) => res.redirect(301, '/signout'));
|
||||
|
||||
function getEmailSignin(req, res) {
|
||||
if (isSignUpDisabled) {
|
||||
return res.render('account/beta', {
|
||||
title: 'New sign ups are disabled'
|
||||
});
|
||||
}
|
||||
return res.render('account/email-signin', {
|
||||
title: 'Sign in to freeCodeCamp using your Email Address'
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/signup', ifUserRedirect, getEmailSignin);
|
||||
router.get('/signin', ifUserRedirect, getEmailSignin);
|
||||
router.get('/email-signin', ifUserRedirect, getEmailSignin);
|
||||
|
||||
router.get('/signout', (req, res) => {
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
|
||||
router.get(
|
||||
'/deprecated-signin',
|
||||
ifUserRedirect,
|
||||
(req, res) => res.render('account/deprecated-signin', {
|
||||
title: 'Sign in to freeCodeCamp using a Deprecated Login'
|
||||
})
|
||||
);
|
||||
|
||||
const defaultErrorMsg = dedent`
|
||||
Oops, something is not right,
|
||||
please request a fresh link to sign in / sign up.
|
||||
`;
|
||||
|
||||
const passwordlessGetValidators = [
|
||||
check('email')
|
||||
.isBase64()
|
||||
.withMessage('Email should be a base64 encoded string.'),
|
||||
check('token')
|
||||
.exists()
|
||||
.withMessage('Token should exist.')
|
||||
// based on strongloop/loopback/common/models/access-token.js#L15
|
||||
.isLength({ min: 64, max: 64 })
|
||||
.withMessage('Token is not the right length.')
|
||||
];
|
||||
|
||||
function getPasswordlessAuth(req, res, next) {
|
||||
const {
|
||||
query: {
|
||||
email: encodedEmail,
|
||||
token: authTokenId
|
||||
} = {}
|
||||
} = req;
|
||||
const validation = validationResult(req)
|
||||
.formatWith(createValidatorErrorFormatter('errors', '/email-signup'));
|
||||
|
||||
if (!validation.isEmpty()) {
|
||||
const errors = validation.array();
|
||||
return next(errors.pop());
|
||||
}
|
||||
|
||||
const email = User.decodeEmail(encodedEmail);
|
||||
if (!isEmail(email)) {
|
||||
return next(wrapHandledError(
|
||||
new TypeError('decoded email is invalid'),
|
||||
{
|
||||
type: 'info',
|
||||
message: 'The email encoded in the link is incorrectly formatted',
|
||||
redirectTo: '/email-sign'
|
||||
}
|
||||
));
|
||||
}
|
||||
// first find
|
||||
return AuthToken.findOne$({ where: { id: authTokenId } })
|
||||
.flatMap(authToken => {
|
||||
if (!authToken) {
|
||||
throw wrapHandledError(
|
||||
new Error(`no token found for id: ${authTokenId}`),
|
||||
{
|
||||
type: 'info',
|
||||
message: defaultErrorMsg,
|
||||
redirectTo: '/email-signin'
|
||||
}
|
||||
);
|
||||
}
|
||||
// find user then validate and destroy email validation token
|
||||
// finally retun user instance
|
||||
return User.findOne$({ where: { id: authToken.userId } })
|
||||
.flatMap(user => {
|
||||
if (!user) {
|
||||
throw wrapHandledError(
|
||||
new Error(`no user found for token: ${authTokenId}`),
|
||||
{
|
||||
type: 'info',
|
||||
message: defaultErrorMsg,
|
||||
redirectTo: '/email-signin'
|
||||
}
|
||||
);
|
||||
}
|
||||
if (user.email !== email) {
|
||||
throw wrapHandledError(
|
||||
new Error('user email does not match'),
|
||||
{
|
||||
type: 'info',
|
||||
message: defaultErrorMsg,
|
||||
redirectTo: '/email-signin'
|
||||
}
|
||||
);
|
||||
}
|
||||
return authToken.validate()
|
||||
.map(isValid => {
|
||||
if (!isValid) {
|
||||
throw wrapHandledError(
|
||||
new Error('token is invalid'),
|
||||
{
|
||||
type: 'info',
|
||||
message: `
|
||||
Looks like the link you clicked has expired,
|
||||
please request a fresh link, to sign in.
|
||||
`,
|
||||
redirectTo: '/email-signin'
|
||||
}
|
||||
);
|
||||
}
|
||||
return authToken.destroy();
|
||||
})
|
||||
.map(() => user);
|
||||
});
|
||||
})
|
||||
// at this point token has been validated and destroyed
|
||||
// update user and log them in
|
||||
.map(user => user.loginByRequest(req, res))
|
||||
.do(() => {
|
||||
let redirectTo = '/';
|
||||
|
||||
if (
|
||||
req.session &&
|
||||
req.session.returnTo
|
||||
) {
|
||||
redirectTo = req.session.returnTo;
|
||||
}
|
||||
|
||||
req.flash('success', { msg:
|
||||
'Success! You have signed in to your account. Happy Coding!'
|
||||
});
|
||||
|
||||
return res.redirect(redirectTo);
|
||||
})
|
||||
.subscribe(
|
||||
() => {},
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
router.get(
|
||||
'/passwordless-auth',
|
||||
ifUserRedirect,
|
||||
passwordlessGetValidators,
|
||||
getPasswordlessAuth
|
||||
);
|
||||
|
||||
const passwordlessPostValidators = [
|
||||
check('email')
|
||||
.isEmail()
|
||||
.withMessage('Email is not a valid email address.')
|
||||
];
|
||||
function postPasswordlessAuth(req, res, next) {
|
||||
const { body: { email } = {} } = req;
|
||||
const validation = validationResult(req)
|
||||
.formatWith(createValidatorErrorFormatter('errors', '/email-signup'));
|
||||
if (!validation.isEmpty()) {
|
||||
const errors = validation.array();
|
||||
return next(errors.pop());
|
||||
}
|
||||
|
||||
return User.findOne$({ where: { email } })
|
||||
.flatMap(_user => Observable.if(
|
||||
// if no user found create new user and save to db
|
||||
_.constant(_user),
|
||||
Observable.of(_user),
|
||||
User.create$({ email })
|
||||
)
|
||||
.flatMap(user => user.requestAuthEmail(!_user))
|
||||
)
|
||||
.do(msg => res.status(200).send({ message: msg }))
|
||||
.subscribe(_.noop, next);
|
||||
}
|
||||
|
||||
api.post(
|
||||
'/passwordless-auth',
|
||||
ifUserRedirect,
|
||||
passwordlessPostValidators,
|
||||
postPasswordlessAuth
|
||||
);
|
||||
|
||||
app.use('/:lang', router);
|
||||
app.use(api);
|
||||
};
|
||||
|
@@ -14,9 +14,14 @@ import {
|
||||
import { observeQuery } from '../utils/rx';
|
||||
|
||||
import {
|
||||
respWebDesignId,
|
||||
frontEndLibsId,
|
||||
jsAlgoDataStructId,
|
||||
frontEndChallengeId,
|
||||
dataVisChallengeId,
|
||||
backEndChallengeId
|
||||
dataVisId,
|
||||
apisMicroservicesId,
|
||||
backEndChallengeId,
|
||||
infosecQaId
|
||||
} from '../utils/constantStrings.json';
|
||||
|
||||
import {
|
||||
@@ -60,9 +65,12 @@ function getIdsForCert$(id, Challenge) {
|
||||
// {
|
||||
// email: String,
|
||||
// username: String,
|
||||
// isFrontEndCert: Boolean,
|
||||
// isBackEndCert: Boolean,
|
||||
// isDataVisCert: Boolean
|
||||
// isRespWebDesignCert: Boolean,
|
||||
// isFrontEndLibsCert: Boolean,
|
||||
// isJsAlgoDataStructCert: Boolean,
|
||||
// isDataVisCert: Boolean,
|
||||
// isApisMicroservicesCert: Boolean,
|
||||
// isInfosecQaCert: Boolean
|
||||
// },
|
||||
// send$: Observable
|
||||
// ) => Observable
|
||||
@@ -71,17 +79,23 @@ function sendCertifiedEmail(
|
||||
email,
|
||||
name,
|
||||
username,
|
||||
isFrontEndCert,
|
||||
isBackEndCert,
|
||||
isDataVisCert
|
||||
isRespWebDesignCert,
|
||||
isFrontEndLibsCert,
|
||||
isJsAlgoDataStructCert,
|
||||
isDataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isInfosecQaCert
|
||||
},
|
||||
send$
|
||||
) {
|
||||
if (
|
||||
!isEmail(email) ||
|
||||
!isFrontEndCert ||
|
||||
!isBackEndCert ||
|
||||
!isDataVisCert
|
||||
!isRespWebDesignCert ||
|
||||
!isFrontEndLibsCert ||
|
||||
!isJsAlgoDataStructCert ||
|
||||
!isDataVisCert ||
|
||||
!isApisMicroservicesCert ||
|
||||
!isInfosecQaCert
|
||||
) {
|
||||
return Observable.just(false);
|
||||
}
|
||||
@@ -107,8 +121,16 @@ export default function certificate(app) {
|
||||
|
||||
const certTypeIds = {
|
||||
[certTypes.frontEnd]: getIdsForCert$(frontEndChallengeId, Challenge),
|
||||
[certTypes.dataVis]: getIdsForCert$(dataVisChallengeId, Challenge),
|
||||
[certTypes.backEnd]: getIdsForCert$(backEndChallengeId, Challenge)
|
||||
[certTypes.backEnd]: getIdsForCert$(backEndChallengeId, Challenge),
|
||||
[certTypes.respWebDesign]: getIdsForCert$(respWebDesignId, Challenge),
|
||||
[certTypes.frontEndLibs]: getIdsForCert$(frontEndLibsId, Challenge),
|
||||
[certTypes.jsAlgoDataStruct]: getIdsForCert$(jsAlgoDataStructId, Challenge),
|
||||
[certTypes.dataVis]: getIdsForCert$(dataVisId, Challenge),
|
||||
[certTypes.apisMicroservices]: getIdsForCert$(
|
||||
apisMicroservicesId,
|
||||
Challenge
|
||||
),
|
||||
[certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge)
|
||||
};
|
||||
|
||||
router.post(
|
||||
@@ -123,12 +145,42 @@ export default function certificate(app) {
|
||||
verifyCert.bind(null, certTypes.backEnd)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/responsive-web-design',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.respWebDesign)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/front-end-libraries',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.frontEndLibs)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/javascript-algorithms-data-structures',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.jsAlgoDataStruct)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/data-visualization',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.dataVis)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/apis-microservices',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.apisMicroservices)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/information-security-quality-assurance',
|
||||
ifNoUser401,
|
||||
verifyCert.bind(null, certTypes.infosecQa)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/honest',
|
||||
sendMessageToNonUser,
|
||||
|
@@ -132,7 +132,7 @@ export default function commit(app) {
|
||||
const {
|
||||
nonprofit: nonprofitName = 'girl develop it',
|
||||
amount = '5',
|
||||
goal = commitGoals.frontEndCert
|
||||
goal = commitGoals.respWebDesignCert
|
||||
} = req.query;
|
||||
|
||||
const nonprofit = findNonprofit(nonprofitName);
|
||||
|
@@ -1,15 +1,19 @@
|
||||
const createDebugger = require('debug');
|
||||
|
||||
const log = createDebugger('fcc:boot:explorer');
|
||||
|
||||
module.exports = function mountLoopBackExplorer(app) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return;
|
||||
}
|
||||
var explorer;
|
||||
let explorer;
|
||||
try {
|
||||
explorer = require('loopback-component-explorer');
|
||||
} catch (err) {
|
||||
// Print the message only when the app was started via `app.listen()`.
|
||||
// Do not print any message when the project is used as a component.
|
||||
app.once('started', function() {
|
||||
console.log(
|
||||
log(
|
||||
'Run `npm install loopback-component-explorer` to enable ' +
|
||||
'the LoopBack explorer'
|
||||
);
|
||||
@@ -17,13 +21,13 @@ module.exports = function mountLoopBackExplorer(app) {
|
||||
return;
|
||||
}
|
||||
|
||||
var restApiRoot = app.get('restApiRoot');
|
||||
var mountPath = '/explorer';
|
||||
const restApiRoot = app.get('restApiRoot');
|
||||
const mountPath = '/explorer';
|
||||
|
||||
explorer(app, { basePath: restApiRoot, mountPath });
|
||||
app.once('started', function() {
|
||||
var baseUrl = app.get('url').replace(/\/$/, '');
|
||||
const baseUrl = app.get('url').replace(/\/$/, '');
|
||||
|
||||
console.log('Browse your REST API at %s%s', baseUrl, mountPath);
|
||||
log('Browse your REST API at %s%s', baseUrl, mountPath);
|
||||
});
|
||||
};
|
||||
|
@@ -1,35 +0,0 @@
|
||||
var path = require('path');
|
||||
var loopback = require('loopback');
|
||||
var express = require('express');
|
||||
|
||||
var port = 1337;
|
||||
|
||||
// this will listen to traffic on port 1337
|
||||
// The purpose is to redirect any user who is direct to https
|
||||
// instead of http by mistake. Our nginx proxy server will listen
|
||||
// for https traffic and serve from this port on this server.
|
||||
// the view being send will have a short timeout and a redirect
|
||||
module.exports = function(loopbackApp) {
|
||||
var app = express();
|
||||
app.set('view engine', 'jade');
|
||||
// views in ../views'
|
||||
app.set('views', path.join(__dirname, '..'));
|
||||
|
||||
// server static files
|
||||
app.use(loopback.static(path.join(
|
||||
__dirname,
|
||||
'../',
|
||||
'../public'
|
||||
)));
|
||||
|
||||
// all traffic will be redirected on page load;
|
||||
app.use(function(req, res) {
|
||||
return res.render('views/redirect-https');
|
||||
});
|
||||
|
||||
loopbackApp.once('started', function() {
|
||||
app.listen(port, function() {
|
||||
console.log('https redirect listening on port %s', port);
|
||||
});
|
||||
});
|
||||
};
|
@@ -6,8 +6,13 @@ import emoji from 'node-emoji';
|
||||
|
||||
import {
|
||||
frontEndChallengeId,
|
||||
dataVisChallengeId,
|
||||
backEndChallengeId
|
||||
backEndChallengeId,
|
||||
respWebDesignId,
|
||||
frontEndLibsId,
|
||||
jsAlgoDataStructId,
|
||||
dataVisId,
|
||||
apisMicroservicesId,
|
||||
infosecQaId
|
||||
} from '../utils/constantStrings.json';
|
||||
import certTypes from '../utils/certTypes.json';
|
||||
import {
|
||||
@@ -24,27 +29,44 @@ import {
|
||||
import supportedLanguages from '../../common/utils/supported-languages';
|
||||
import { getChallengeInfo, cachedMap } from '../utils/map';
|
||||
|
||||
const isSignUpDisabled = !!process.env.DISABLE_SIGNUP;
|
||||
const debug = debugFactory('fcc:boot:user');
|
||||
const sendNonUserToMap = ifNoUserRedirectTo('/map');
|
||||
const certIds = {
|
||||
[certTypes.frontEnd]: frontEndChallengeId,
|
||||
[certTypes.dataVis]: dataVisChallengeId,
|
||||
[certTypes.backEnd]: backEndChallengeId
|
||||
[certTypes.backEnd]: backEndChallengeId,
|
||||
[certTypes.respWebDesign]: respWebDesignId,
|
||||
[certTypes.frontEndLibs]: frontEndLibsId,
|
||||
[certTypes.jsAlgoDataStruct]: jsAlgoDataStructId,
|
||||
[certTypes.dataVis]: dataVisId,
|
||||
[certTypes.apisMicroservices]: apisMicroservicesId,
|
||||
[certTypes.infosecQa]: infosecQaId
|
||||
};
|
||||
|
||||
const certViews = {
|
||||
[certTypes.frontEnd]: 'certificate/front-end.jade',
|
||||
[certTypes.dataVis]: 'certificate/data-vis.jade',
|
||||
[certTypes.backEnd]: 'certificate/back-end.jade',
|
||||
[certTypes.fullStack]: 'certificate/full-stack.jade'
|
||||
[certTypes.fullStack]: 'certificate/full-stack.jade',
|
||||
[certTypes.respWebDesign]: 'certificate/responsive-web-design.jade',
|
||||
[certTypes.frontEndLibs]: 'certificate/front-end-libraries.jade',
|
||||
[certTypes.jsAlgoDataStruct]:
|
||||
'certificate/javascript-algorithms-and-data-structures.jade',
|
||||
[certTypes.dataVis]: 'certificate/data-visualization.jade',
|
||||
[certTypes.apisMicroservices]: 'certificate/apis-and-microservices.jade',
|
||||
[certTypes.infosecQa]:
|
||||
'certificate/information-security-and-quality-assurance.jade'
|
||||
};
|
||||
|
||||
const certText = {
|
||||
[certTypes.frontEnd]: 'Front End certified',
|
||||
[certTypes.dataVis]: 'Data Vis Certified',
|
||||
[certTypes.backEnd]: 'Back End Certified',
|
||||
[certTypes.fullStack]: 'Full Stack Certified'
|
||||
[certTypes.fullStack]: 'Full Stack Certified',
|
||||
[certTypes.respWebDesign]: 'Responsive Web Design Certified',
|
||||
[certTypes.frontEndLibs]: 'Front End Libraries Certified',
|
||||
[certTypes.jsAlgoDataStruct]:
|
||||
'JavaScript Algorithms and Data Structures Certified',
|
||||
[certTypes.dataVis]: 'Data Visualization Certified',
|
||||
[certTypes.apisMicroservices]: 'APIs and Microservices Certified',
|
||||
[certTypes.infosecQa]: 'Information Security and Quality Assurance Certified'
|
||||
};
|
||||
|
||||
const dateFormat = 'MMM DD, YYYY';
|
||||
@@ -139,7 +161,7 @@ function buildDisplayChallenges(
|
||||
module.exports = function(app) {
|
||||
const router = app.loopback.Router();
|
||||
const api = app.loopback.Router();
|
||||
const { AccessToken, Email, User } = app.models;
|
||||
const { Email, User } = app.models;
|
||||
const map$ = cachedMap(app.models);
|
||||
|
||||
function findUserByUsername$(username, fields) {
|
||||
@@ -153,23 +175,6 @@ module.exports = function(app) {
|
||||
);
|
||||
}
|
||||
|
||||
AccessToken.findOne$ = Observable.fromNodeCallback(
|
||||
AccessToken.findOne, AccessToken
|
||||
);
|
||||
|
||||
router.get('/login', function(req, res) {
|
||||
res.redirect(301, '/signin');
|
||||
});
|
||||
router.get('/logout', function(req, res) {
|
||||
res.redirect(301, '/signout');
|
||||
});
|
||||
router.get('/signup', getEmailSignin);
|
||||
router.get('/signin', getEmailSignin);
|
||||
router.get('/signout', signout);
|
||||
router.get('/email-signin', getEmailSignin);
|
||||
router.get('/deprecated-signin', getDepSignin);
|
||||
router.get('/passwordless-auth', invalidateAuthToken, getPasswordlessAuth);
|
||||
api.post('/passwordless-auth', postPasswordlessAuth);
|
||||
router.get(
|
||||
'/delete-my-account',
|
||||
sendNonUserToMap,
|
||||
@@ -208,11 +213,6 @@ module.exports = function(app) {
|
||||
showCert.bind(null, certTypes.frontEnd)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/data-visualization-certification',
|
||||
showCert.bind(null, certTypes.dataVis)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/back-end-certification',
|
||||
showCert.bind(null, certTypes.backEnd)
|
||||
@@ -223,6 +223,36 @@ module.exports = function(app) {
|
||||
(req, res) => res.redirect(req.url.replace('full-stack', 'back-end'))
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/responsive-web-design-certification',
|
||||
showCert.bind(null, certTypes.respWebDesign)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/front-end-libraries-certification',
|
||||
showCert.bind(null, certTypes.frontEndLibs)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/javascript-algorithms-data-structures-certification',
|
||||
showCert.bind(null, certTypes.jsAlgoDataStruct)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/data-visualization-certification',
|
||||
showCert.bind(null, certTypes.dataVis)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/apis-microservices-certification',
|
||||
showCert.bind(null, certTypes.apisMicroservices)
|
||||
);
|
||||
|
||||
api.get(
|
||||
'/:username/information-security-quality-assurance-certification',
|
||||
showCert.bind(null, certTypes.infosecQa)
|
||||
);
|
||||
|
||||
router.get('/:username', showUserProfile);
|
||||
router.get(
|
||||
'/:username/report-user/',
|
||||
@@ -240,179 +270,6 @@ module.exports = function(app) {
|
||||
app.use('/:lang', router);
|
||||
app.use(api);
|
||||
|
||||
const defaultErrorMsg = [ 'Oops, something is not right, please request a ',
|
||||
'fresh link to sign in / sign up.' ].join('');
|
||||
|
||||
function postPasswordlessAuth(req, res) {
|
||||
if (req.user || !(req.body && req.body.email)) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
|
||||
return User.requestAuthEmail(req.body.email)
|
||||
.then(msg => {
|
||||
return res.status(200).send({ message: msg });
|
||||
})
|
||||
.catch(err => {
|
||||
debug(err);
|
||||
return res.status(200).send({ message: defaultErrorMsg });
|
||||
});
|
||||
}
|
||||
|
||||
function invalidateAuthToken(req, res, next) {
|
||||
if (req.user) {
|
||||
res.redirect('/');
|
||||
}
|
||||
|
||||
if (!req.query || !req.query.email || !req.query.token) {
|
||||
req.flash('info', { msg: defaultErrorMsg });
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
|
||||
const authTokenId = req.query.token;
|
||||
const authEmailId = new Buffer(req.query.email, 'base64').toString();
|
||||
|
||||
return AccessToken.findOne$({ where: {id: authTokenId} })
|
||||
.map(authToken => {
|
||||
if (!authToken) {
|
||||
req.flash('info', { msg: defaultErrorMsg });
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
|
||||
const userId = authToken.userId;
|
||||
return User.findById(userId, (err, user) => {
|
||||
if (err || !user || user.email !== authEmailId) {
|
||||
debug(err);
|
||||
req.flash('info', { msg: defaultErrorMsg });
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
return authToken.validate((err, isValid) => {
|
||||
if (err) { throw err; }
|
||||
if (!isValid) {
|
||||
req.flash('info', { msg: [ 'Looks like the link you clicked has',
|
||||
'expired, please request a fresh link, to sign in.'].join('')
|
||||
});
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
return authToken.destroy((err) => {
|
||||
if (err) { debug(err); }
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.subscribe(
|
||||
() => {},
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
function getPasswordlessAuth(req, res, next) {
|
||||
if (req.user) {
|
||||
req.flash('info', {
|
||||
msg: 'Hey, looks like you’re already signed in.'
|
||||
});
|
||||
return res.redirect('/');
|
||||
}
|
||||
|
||||
if (!req.query || !req.query.email || !req.query.token) {
|
||||
req.flash('info', { msg: defaultErrorMsg });
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
|
||||
const email = new Buffer(req.query.email, 'base64').toString();
|
||||
|
||||
return User.findOne$({ where: { email }})
|
||||
.map(user => {
|
||||
|
||||
if (!user) {
|
||||
debug(`did not find a valid user with email: ${email}`);
|
||||
req.flash('info', { msg: defaultErrorMsg });
|
||||
return res.redirect('/email-signin');
|
||||
}
|
||||
|
||||
const emailVerified = true;
|
||||
const emailAuthLinkTTL = null;
|
||||
const emailVerifyTTL = null;
|
||||
user.update$({
|
||||
emailVerified, emailAuthLinkTTL, emailVerifyTTL
|
||||
})
|
||||
.do((user) => {
|
||||
user.emailVerified = emailVerified;
|
||||
user.emailAuthLinkTTL = emailAuthLinkTTL;
|
||||
user.emailVerifyTTL = emailVerifyTTL;
|
||||
});
|
||||
|
||||
return user.createAccessToken(
|
||||
{ ttl: User.settings.ttl }, (err, accessToken) => {
|
||||
if (err) { throw err; }
|
||||
|
||||
var config = {
|
||||
signed: !!req.signedCookies,
|
||||
maxAge: accessToken.ttl
|
||||
};
|
||||
|
||||
if (accessToken && accessToken.id) {
|
||||
debug('setting cookies');
|
||||
res.cookie('access_token', accessToken.id, config);
|
||||
res.cookie('userId', accessToken.userId, config);
|
||||
}
|
||||
|
||||
return req.logIn({
|
||||
id: accessToken.userId.toString() }, err => {
|
||||
if (err) { return next(err); }
|
||||
|
||||
debug('user logged in');
|
||||
|
||||
if (req.session && req.session.returnTo) {
|
||||
var redirectTo = req.session.returnTo;
|
||||
if (redirectTo === '/map-aside') {
|
||||
redirectTo = '/map';
|
||||
}
|
||||
return res.redirect(redirectTo);
|
||||
}
|
||||
|
||||
req.flash('success', { msg:
|
||||
'Success! You have signed in to your account. Happy Coding!'
|
||||
});
|
||||
return res.redirect('/');
|
||||
});
|
||||
});
|
||||
})
|
||||
.subscribe(
|
||||
() => {},
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
function signout(req, res) {
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
}
|
||||
|
||||
|
||||
function getDepSignin(req, res) {
|
||||
if (req.user) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
return res.render('account/deprecated-signin', {
|
||||
title: 'Sign in to freeCodeCamp using a Deprecated Login'
|
||||
});
|
||||
}
|
||||
|
||||
function getEmailSignin(req, res) {
|
||||
if (req.user) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
if (isSignUpDisabled) {
|
||||
return res.render('account/beta', {
|
||||
title: 'New sign ups are disabled'
|
||||
});
|
||||
}
|
||||
return res.render('account/email-signin', {
|
||||
title: 'Sign in to freeCodeCamp using your Email Address'
|
||||
});
|
||||
}
|
||||
|
||||
function getAccount(req, res) {
|
||||
const { username } = req.user;
|
||||
return res.redirect('/' + username);
|
||||
@@ -586,9 +443,14 @@ module.exports = function(app) {
|
||||
isLocked: true,
|
||||
isAvailableForHire: true,
|
||||
isFrontEndCert: true,
|
||||
isDataVisCert: true,
|
||||
isBackEndCert: true,
|
||||
isFullStackCert: true,
|
||||
isRespWebDesignCert: true,
|
||||
isFrontEndLibsCert: true,
|
||||
isJsAlgoDataStructCert: true,
|
||||
isDataVisCert: true,
|
||||
isApisMicroservicesCert: true,
|
||||
isInfosecQaCert: true,
|
||||
isHonest: true,
|
||||
username: true,
|
||||
name: true,
|
||||
|
Reference in New Issue
Block a user