Merge pull request #5001 from FreeCodeCamp/feature/disable-javascript

Add ability to disable user code on page load
This commit is contained in:
Rex Schrader
2015-12-03 17:51:14 -08:00
4 changed files with 49 additions and 15 deletions

View File

@ -42,6 +42,8 @@ window.common = (function(global) {
return decoded return decoded
.split('?') .split('?')
.splice(1) .splice(1)
.pop()
.split('&')
.reduce(function(found, param) { .reduce(function(found, param) {
var key = param.split('=')[0]; var key = param.split('=')[0];
if (key === 'solution') { if (key === 'solution') {
@ -55,6 +57,23 @@ window.common = (function(global) {
codeUri.isInQuery(location.search) || codeUri.isInQuery(location.search) ||
codeUri.isInQuery(location.hash); codeUri.isInQuery(location.hash);
}, },
getKeyInQuery(query, keyToFind = '') {
return query
.split('&')
.reduce(function(oldValue, param) {
var key = param.split('=')[0];
var value = param.split('=')[1];
if (key === keyToFind) {
return value;
}
return oldValue;
}, null);
},
getSolutionFromQuery(query = '') {
return decodeFcc(
codeUri.decode(codeUri.getKeyInQuery(query, 'solution'))
);
},
parse: function() { parse: function() {
if (!codeUri.enabled) { if (!codeUri.enabled) {
return null; return null;
@ -62,6 +81,7 @@ window.common = (function(global) {
var query; var query;
if (location.search && codeUri.isInQuery(location.search)) { if (location.search && codeUri.isInQuery(location.search)) {
query = location.search.replace(/^\?/, ''); query = location.search.replace(/^\?/, '');
if (history && typeof history.replaceState === 'function') { if (history && typeof history.replaceState === 'function') {
history.replaceState( history.replaceState(
history.state, history.state,
@ -73,30 +93,29 @@ window.common = (function(global) {
} else { } else {
query = location.hash.replace(/^\#\?/, ''); query = location.hash.replace(/^\#\?/, '');
} }
if (!query) { if (!query) {
return null; return null;
} }
return query return this.getSolutionFromQuery(query);
.split('&')
.reduce(function(solution, param) {
var key = param.split('=')[0];
var value = param.split('=')[1];
if (key === 'solution') {
return decodeFcc(codeUri.decode(value || ''));
}
return solution;
}, null);
}, },
querify: function(solution) { querify: function(solution) {
if (!codeUri.enabled) { if (!codeUri.enabled) {
return null; return null;
} }
if (history && typeof history.replaceState === 'function') { if (history && typeof history.replaceState === 'function') {
// grab the url up to the query
// destroy any hash symbols still clinging to life
const url = (location.href.split('?')[0]).replace(/(#*)$/, '');
history.replaceState( history.replaceState(
history.state, history.state,
null, null,
'?solution=' + codeUri.encode(encodeFcc(solution)) url +
'#?' +
(codeUri.shouldRun() ? '' : 'run=disabled&') +
'solution=' +
codeUri.encode(encodeFcc(solution))
); );
} else { } else {
location.hash = '?solution=' + location.hash = '?solution=' +
@ -105,7 +124,13 @@ window.common = (function(global) {
return solution; return solution;
}, },
enabled: true enabled: true,
shouldRun() {
return !this.getKeyInQuery(
(location.search || location.hash).replace(/^(\?|#\?)/, ''),
'run'
);
}
}; };
common.init.push(function() { common.init.push(function() {
@ -113,6 +138,7 @@ window.common = (function(global) {
}); });
common.codeUri = codeUri; common.codeUri = codeUri;
common.shouldRun = () => codeUri.shouldRun();
return common; return common;
}(window)); }(window));

View File

@ -34,6 +34,11 @@ window.common = (function(global) {
body { padding: 0px 3px 0px 3px; } body { padding: 0px 3px 0px 3px; }
</style> </style>
`; `;
const codeDisabledError = `
<script>
window.__err = new Error('code has been disabled');
</script>
`;
const iFrameScript$ = const iFrameScript$ =
common.getScriptContent$('/js/iFrameScripts.js').shareReplay(); common.getScriptContent$('/js/iFrameScripts.js').shareReplay();
@ -74,7 +79,7 @@ window.common = (function(global) {
preview.write( preview.write(
libraryIncludes + libraryIncludes +
jQuery + jQuery +
code + (common.shouldRun() ? code : codeDisabledError) +
'<!-- -->' + '<!-- -->' +
iframeScript iframeScript
); );

View File

@ -11,6 +11,9 @@ window.$(document).ready(function() {
var common = parent.common; var common = parent.common;
common.getJsOutput = function evalJs(code = '') { common.getJsOutput = function evalJs(code = '') {
if (window.__err || !common.shouldRun()) {
return window.__err || 'code disabled';
}
let output; let output;
try { try {
/* eslint-disable no-eval */ /* eslint-disable no-eval */

View File

@ -20,6 +20,7 @@ if (typeof DEBUG === 'undefined') { DEBUG = true; }
var reSingle = /\b(for|while|do)\b/; var reSingle = /\b(for|while|do)\b/;
var labelRe = /\b([a-z_]{1}\w+:)/i; var labelRe = /\b([a-z_]{1}\w+:)/i;
var comments = /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm; var comments = /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm;
var loopTimeout = 500;
var loopProtect = rewriteLoops; var loopProtect = rewriteLoops;
@ -404,8 +405,7 @@ if (typeof DEBUG === 'undefined') { DEBUG = true; }
} }
line.hit++; line.hit++;
if ((now - line.time) > 100) {//} && line.hit !== line.last+1) { if ((now - line.time) > loopTimeout) {//} && line.hit !== line.last+1) {
// We've spent over 100ms on this loop... smells infinite.
loopProtect.hit(state.line); loopProtect.hit(state.line);
// Returning true prevents the loop running again // Returning true prevents the loop running again
return true; return true;