Fix jQuery challenges

This commit is contained in:
Berkeley Martinez
2015-11-24 13:48:14 -08:00
parent 159b202940
commit eec7fff909
6 changed files with 90 additions and 70 deletions

1
.gitignore vendored
View File

@ -45,6 +45,7 @@ public/js/sandbox*
public/js/iFrameScripts*
public/js/plugin*
public/js/vendor*
public/js/faux*
public/css/main*
server/rev-manifest.json

View File

@ -0,0 +1,55 @@
window.common = (function(global) {
const {
Rx: { Observable },
common = { init: [] }
} = global;
const detectFunctionCall = /function\s*?\(|function\s+\w+\s*?\(/gi;
const detectUnsafeJQ = /\$\s*?\(\s*?\$\s*?\)/gi;
const detectUnsafeConsoleCall = /if\s\(null\)\sconsole\.log\(1\);/gi;
common.detectUnsafeCode$ = function detectUnsafeCode$(code) {
const openingComments = code.match(/\/\*/gi);
const closingComments = code.match(/\*\//gi);
// checks if the number of opening comments(/*) matches the number of
// closing comments(*/)
if (
openingComments &&
(
!closingComments ||
openingComments.length > closingComments.length
)
) {
return Observable.throw(
new Error('SyntaxError: Unfinished multi-line comment')
);
}
if (code.match(detectUnsafeJQ)) {
return Observable.throw(
new Error('Unsafe $($)')
);
}
if (
code.match(/function/g) &&
!code.match(detectFunctionCall)
) {
return Observable.throw(
new Error('SyntaxError: Unsafe or unfinished function declaration')
);
}
if (code.match(detectUnsafeConsoleCall)) {
return Observable.throw(
new Error('Invalid if (null) console.log(1); detected')
);
}
return Observable.just(code);
};
return common;
}(window));

View File

@ -26,7 +26,8 @@ $(document).ready(function() {
code$
.flatMap(code => {
if (common.hasJs(code)) {
return common.detectLoops$(code)
return common.detectUnsafeCode$(code)
.flatMap(code => common.detectLoops$(code))
.flatMap(
({ err }) => err ? Observable.throw(err) : Observable.just(code)
);
@ -101,12 +102,13 @@ $(document).ready(function() {
}
);
// initial challenge run to populate tests
if (challengeType === challengeTypes.HTML) {
var $preview = $('#preview');
return Observable.fromCallback($preview.ready, $preview)()
.delay(500)
.flatMap(() => common.executeChallenge$())
.catch(err => Observable.just(err))
.catch(err => Observable.just({ err }))
.subscribe(
({ err, tests }) => {
if (err) {

View File

@ -12,9 +12,6 @@ window.common = (function(global) {
} = global;
let attempts = 0;
const detectFunctionCall = /function\s*?\(|function\s+\w+\s*?\(/gi;
const detectUnsafeJQ = /\$\s*?\(\s*?\$\s*?\)/gi;
const detectUnsafeConsoleCall = /if\s\(null\)\sconsole\.log\(1\);/gi;
common.executeChallenge$ = function executeChallenge$() {
const code = common.editor.getValue();
@ -25,101 +22,62 @@ window.common = (function(global) {
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
let openingComments = code.match(/\/\*/gi);
// checks if the number of opening comments(/*) matches the number of
// closing comments(*/)
return Observable.just({ code })
.flatMap(({ code }) => {
if (
code.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
openingComments &&
openingComments.length > code.match(/\*\//gi).length
) {
return Observable.throw({
err: 'SyntaxError: Unfinished multi-line comment',
code
});
}
if (code.match(detectUnsafeJQ)) {
return Observable.throw({
err: 'Unsafe $($)',
code
});
}
if (
code.match(/function/g) &&
!code.match(detectFunctionCall)
) {
return Observable.throw({
err: 'SyntaxError: Unsafe or unfinished function declaration',
code
});
}
if (code.match(detectUnsafeConsoleCall)) {
return Observable.throw({
err: 'Invalid if (null) console.log(1); detected',
code
});
}
// add head and tail and detect loops
return Observable.just({ code: head + code + tail, original: code });
})
.flatMap(data => {
// run checks for unsafe code
return common.detectUnsafeCode$(code)
// add head and tail and detect loops
.map(code => head + code + tail)
.flatMap(code => {
if (common.challengeType === common.challengeTypes.HTML) {
if (common.hasJs(code)) {
return common.addFaux$(data)
// html has a script code
// add faux code and test in webworker
return common.addFaux$(code)
.flatMap(code => common.detectLoops$(code))
.flatMap(({ err }) => {
if (err) {
return Observable.throw({ err });
return Observable.throw(err);
}
return common.runPreviewTests$({
code: data.code,
tests: common.tests.slice()
});
return common.updatePreview$(code)
.flatMap(() => common.runPreviewTests$({
code,
tests: common.tests.slice()
}));
});
}
return common.updatePreview$(data.code)
// no script code detected in html code
// Update preview and run tests in iframe
return common.updatePreview$(code)
.flatMap(code => common.runPreviewTests$({
code,
tests: common.tests.slice()
}));
}
// js challenge
// remove comments and add tests to string
return common.addTestsToString(Object.assign(
data,
{
code: common.removeComments(code),
tests: common.tests.slice()
}
))
.flatMap(common.detectLoops$)
.flatMap(({ err, code, data, userTests, original }) => {
.flatMap(({ err, code, data, userTests }) => {
if (err) {
return Observable.throw({ err });
return Observable.throw(err);
}
// run tests
// for now these are running in the browser
return common.runTests$({
data,
code,
userTests,
original,
output: data.output.replace(/\\\"/gi, '')
});
});
})
.catch(e => {
return e && e.err ?
Observable.throw(e) :
Observable.throw({ err: e });
});
};

View File

@ -1,8 +1,9 @@
document = {};
/* eslint-disable no-unused-vars */
var document = {};
var navigator = function() {
this.geolocation = function() {
this.getCurrentPosition = function() {
this.coords = {latitude: "", longitude: ""};
this.coords = {latitude: '', longitude: '' };
return this;
};
return this;

View File

@ -103,7 +103,8 @@ var paths = {
js: [
'client/main.js',
'client/iFrameScripts.js',
'client/plugin.js'
'client/plugin.js',
'client/faux.js'
],
commonFramework: [
@ -114,6 +115,7 @@ var paths = {
'code-storage',
'code-uri',
'create-editor',
'detect-unsafe-code-stream',
'detect-loops-stream',
'display-test-results',
'execute-challenge-stream',
@ -421,6 +423,7 @@ gulp.task('js', function() {
});
// commonFramework depend on iFrameScripts
// and faux.js
gulp.task('dependents', ['js'], function() {
var manifestName = 'dependents-manifest.json';
var dest = paths.publicJs;