Fix jQuery challenges
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -45,6 +45,7 @@ public/js/sandbox*
|
|||||||
public/js/iFrameScripts*
|
public/js/iFrameScripts*
|
||||||
public/js/plugin*
|
public/js/plugin*
|
||||||
public/js/vendor*
|
public/js/vendor*
|
||||||
|
public/js/faux*
|
||||||
public/css/main*
|
public/css/main*
|
||||||
|
|
||||||
server/rev-manifest.json
|
server/rev-manifest.json
|
||||||
|
55
client/commonFramework/detect-unsafe-code-stream.js
Normal file
55
client/commonFramework/detect-unsafe-code-stream.js
Normal 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));
|
@ -26,7 +26,8 @@ $(document).ready(function() {
|
|||||||
code$
|
code$
|
||||||
.flatMap(code => {
|
.flatMap(code => {
|
||||||
if (common.hasJs(code)) {
|
if (common.hasJs(code)) {
|
||||||
return common.detectLoops$(code)
|
return common.detectUnsafeCode$(code)
|
||||||
|
.flatMap(code => common.detectLoops$(code))
|
||||||
.flatMap(
|
.flatMap(
|
||||||
({ err }) => err ? Observable.throw(err) : Observable.just(code)
|
({ 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) {
|
if (challengeType === challengeTypes.HTML) {
|
||||||
var $preview = $('#preview');
|
var $preview = $('#preview');
|
||||||
return Observable.fromCallback($preview.ready, $preview)()
|
return Observable.fromCallback($preview.ready, $preview)()
|
||||||
.delay(500)
|
.delay(500)
|
||||||
.flatMap(() => common.executeChallenge$())
|
.flatMap(() => common.executeChallenge$())
|
||||||
.catch(err => Observable.just(err))
|
.catch(err => Observable.just({ err }))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
({ err, tests }) => {
|
({ err, tests }) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -12,9 +12,6 @@ window.common = (function(global) {
|
|||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
let attempts = 0;
|
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$() {
|
common.executeChallenge$ = function executeChallenge$() {
|
||||||
const code = common.editor.getValue();
|
const code = common.editor.getValue();
|
||||||
@ -25,101 +22,62 @@ window.common = (function(global) {
|
|||||||
|
|
||||||
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
|
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
|
||||||
|
|
||||||
let openingComments = code.match(/\/\*/gi);
|
// run checks for unsafe code
|
||||||
|
return common.detectUnsafeCode$(code)
|
||||||
// checks if the number of opening comments(/*) matches the number of
|
// add head and tail and detect loops
|
||||||
// closing comments(*/)
|
.map(code => head + code + tail)
|
||||||
return Observable.just({ code })
|
.flatMap(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 => {
|
|
||||||
if (common.challengeType === common.challengeTypes.HTML) {
|
if (common.challengeType === common.challengeTypes.HTML) {
|
||||||
|
|
||||||
if (common.hasJs(code)) {
|
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(code => common.detectLoops$(code))
|
||||||
.flatMap(({ err }) => {
|
.flatMap(({ err }) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return Observable.throw({ err });
|
return Observable.throw(err);
|
||||||
}
|
}
|
||||||
return common.runPreviewTests$({
|
return common.updatePreview$(code)
|
||||||
code: data.code,
|
.flatMap(() => common.runPreviewTests$({
|
||||||
tests: common.tests.slice()
|
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$({
|
.flatMap(code => common.runPreviewTests$({
|
||||||
code,
|
code,
|
||||||
tests: common.tests.slice()
|
tests: common.tests.slice()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// js challenge
|
||||||
|
// remove comments and add tests to string
|
||||||
return common.addTestsToString(Object.assign(
|
return common.addTestsToString(Object.assign(
|
||||||
data,
|
|
||||||
{
|
{
|
||||||
code: common.removeComments(code),
|
code: common.removeComments(code),
|
||||||
tests: common.tests.slice()
|
tests: common.tests.slice()
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
.flatMap(common.detectLoops$)
|
.flatMap(common.detectLoops$)
|
||||||
.flatMap(({ err, code, data, userTests, original }) => {
|
.flatMap(({ err, code, data, userTests }) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return Observable.throw({ err });
|
return Observable.throw(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run tests
|
||||||
|
// for now these are running in the browser
|
||||||
return common.runTests$({
|
return common.runTests$({
|
||||||
data,
|
data,
|
||||||
code,
|
code,
|
||||||
userTests,
|
userTests,
|
||||||
original,
|
|
||||||
output: data.output.replace(/\\\"/gi, '')
|
output: data.output.replace(/\\\"/gi, '')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
return e && e.err ?
|
|
||||||
Observable.throw(e) :
|
|
||||||
Observable.throw({ err: e });
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
document = {};
|
/* eslint-disable no-unused-vars */
|
||||||
|
var document = {};
|
||||||
var navigator = function() {
|
var navigator = function() {
|
||||||
this.geolocation = function() {
|
this.geolocation = function() {
|
||||||
this.getCurrentPosition = function() {
|
this.getCurrentPosition = function() {
|
||||||
this.coords = {latitude: "", longitude: ""};
|
this.coords = {latitude: '', longitude: '' };
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
return this;
|
return this;
|
||||||
|
@ -103,7 +103,8 @@ var paths = {
|
|||||||
js: [
|
js: [
|
||||||
'client/main.js',
|
'client/main.js',
|
||||||
'client/iFrameScripts.js',
|
'client/iFrameScripts.js',
|
||||||
'client/plugin.js'
|
'client/plugin.js',
|
||||||
|
'client/faux.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
commonFramework: [
|
commonFramework: [
|
||||||
@ -114,6 +115,7 @@ var paths = {
|
|||||||
'code-storage',
|
'code-storage',
|
||||||
'code-uri',
|
'code-uri',
|
||||||
'create-editor',
|
'create-editor',
|
||||||
|
'detect-unsafe-code-stream',
|
||||||
'detect-loops-stream',
|
'detect-loops-stream',
|
||||||
'display-test-results',
|
'display-test-results',
|
||||||
'execute-challenge-stream',
|
'execute-challenge-stream',
|
||||||
@ -421,6 +423,7 @@ gulp.task('js', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// commonFramework depend on iFrameScripts
|
// commonFramework depend on iFrameScripts
|
||||||
|
// and faux.js
|
||||||
gulp.task('dependents', ['js'], function() {
|
gulp.task('dependents', ['js'], function() {
|
||||||
var manifestName = 'dependents-manifest.json';
|
var manifestName = 'dependents-manifest.json';
|
||||||
var dest = paths.publicJs;
|
var dest = paths.publicJs;
|
||||||
|
Reference in New Issue
Block a user