Fix(routing): add protections against malformed data

This commit is contained in:
Berkeley Martinez
2016-08-05 14:49:23 -07:00
parent 91a50b4843
commit 3d05eee0ea
4 changed files with 84 additions and 55 deletions

View File

@ -1,5 +1,6 @@
import { compose } from 'redux'; import { compose } from 'redux';
import { bonfire, html, js } from '../../utils/challengeTypes'; import { bonfire, html, js } from '../../utils/challengeTypes';
import protect from '../../utils/empty-protector';
export function encodeScriptTags(value) { export function encodeScriptTags(value) {
return value return value
@ -78,19 +79,6 @@ export function loggerToStr(args) {
.reduce((str, arg) => str + arg + '\n', ''); .reduce((str, arg) => str + arg + '\n', '');
} }
export function getFirstChallenge(
{ superBlock, block, challenge },
result
) {
return challenge[
block[
superBlock[
result[0]
].blocks[0]
].challenges[0]
];
}
export function getNextChallenge( export function getNextChallenge(
current, current,
entities, entities,
@ -285,20 +273,6 @@ export function getMouse(e, [dx, dy]) {
return [pageX - dx, pageY - dy]; return [pageX - dx, pageY - dy];
} }
const emptyProtector = {
blocks: [],
challenges: []
};
// protect against malformed data
function protect(block) {
// if no block or block has no challenges or blocks
// use protector
if (!block || !(block.challenges || block.blocks)) {
return emptyProtector;
}
return block;
}
// interface Node { // interface Node {
// isHidden: Boolean, // isHidden: Boolean,
// children: Void|[ ...Node ], // children: Void|[ ...Node ],

View File

@ -0,0 +1,13 @@
const emptyProtector = {
blocks: [],
challenges: []
};
// protect against malformed map data
// protect(block: { challenges: [], block: [] }|Void) => block|emptyProtector
export default function protect(block) {
// if no block or block has no challenges or blocks
if (!block || !(block.challenges || block.blocks)) {
return emptyProtector;
}
return block;
}

View File

@ -0,0 +1,44 @@
import emptyProtector from '../app/utils/empty-protector';
export function checkMapData(
{
entities: {
challenge,
block,
superBlock,
challengeIdToName
},
result
}
) {
if (
!challenge ||
!block ||
!superBlock ||
!challengeIdToName ||
!result ||
!result.length
) {
throw new Error(
'entities not found, db may not be properly seeded. Crashing hard'
);
}
}
// getFirstChallenge(
// map: {
// entities: { challenge: Object, block: Object, superBlock: Object },
// result: [...superBlockDashedName: String]
// }
// ) => Challenge|Void
export function getFirstChallenge({
entities: { superBlock, block, challenge },
result
}) {
return challenge[
emptyProtector(block[
emptyProtector(superBlock[
result[0]
]).blocks[0]
]).challenges[0]
];
}

View File

@ -1,11 +1,15 @@
import _ from 'lodash'; import _ from 'lodash';
// import { Observable, Scheduler } from 'rx';
import debug from 'debug'; import debug from 'debug';
import accepts from 'accepts'; import accepts from 'accepts';
import dedent from 'dedent';
import { ifNoUserSend } from '../utils/middleware'; import { ifNoUserSend } from '../utils/middleware';
import { cachedMap } from '../utils/map'; import { cachedMap } from '../utils/map';
import createNameIdMap from '../../common/utils/create-name-id-map'; import createNameIdMap from '../../common/utils/create-name-id-map';
import {
checkMapData,
getFirstChallenge
} from '../../common/utils/get-first-challenge';
const log = debug('fcc:boot:challenges'); const log = debug('fcc:boot:challenges');
@ -274,40 +278,34 @@ export default function(app) {
result, result,
entities: createNameIdMap(entities) entities: createNameIdMap(entities)
})) }))
.map(({ .map(map => {
result, checkMapData(map);
entities: { const {
challenge: challengeMap, entities: { challenge: challengeMap, challengeIdToName }
block: blockMap, } = map;
superBlock: superBlockMap,
challengeIdToName
}
}) => {
let finalChallenge; let finalChallenge;
const dashedName = challengeIdToName[user && user.currentChallengeId]; const dashedName = challengeIdToName[user && user.currentChallengeId];
finalChallenge = challengeMap[dashedName]; finalChallenge = challengeMap[dashedName];
if (
!challengeMap ||
!blockMap ||
!superBlockMap ||
!result ||
!result.length
) {
throw new Error(
'entities not found, db may not be properly seeded. Crashing hard'
);
}
// redirect to first challenge // redirect to first challenge
if (!finalChallenge) { if (!finalChallenge) {
finalChallenge = challengeMap[ finalChallenge = getFirstChallenge(map);
block[
superBlockMap[
result[0]
].blocks[0]
].challenges[0]
];
} }
const { block, dashedName: finalDashedName } = finalChallenge || {}; const { block, dashedName: finalDashedName } = finalChallenge || {};
if (!finalDashedName || !block) {
// this should normally not be hit if database is properly seeded
console.error(new Error(dedent`
Attemped to find '${dashedName}'
from '${user && user.currentChallengeId || 'no challenge id found'}'
but came up empty.
db may not be properly seeded.
`));
if (dashedName) {
// attempt to find according to dashedName
return `/challenges/${dashedName}`;
} else {
return null;
}
}
return `/challenges/${block}/${finalDashedName}`; return `/challenges/${block}/${finalDashedName}`;
}) })
.subscribe( .subscribe(