Refactoring to use a common request configuration.
Replacing promised-io with bluebird in app.js, loadjs and loadcss Adding linting configurations
This commit is contained in:
Родитель
a59f45e344
Коммит
bc3c4df6ab
|
@ -0,0 +1,12 @@
|
|||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
|
@ -0,0 +1,149 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": false,
|
||||
"node": true,
|
||||
"amd": false,
|
||||
"mocha": true,
|
||||
"jasmine": false
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"no-alert": 2,
|
||||
"no-array-constructor": 2,
|
||||
"no-bitwise": 0,
|
||||
"no-caller": 2,
|
||||
"no-catch-shadow": 2,
|
||||
"no-cond-assign": 2,
|
||||
"no-console": 0,
|
||||
"no-constant-condition": 2,
|
||||
"no-control-regex": 2,
|
||||
"no-debugger": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-div-regex": 0,
|
||||
"no-dupe-keys": 2,
|
||||
"no-else-return": 0,
|
||||
"no-empty": 2,
|
||||
"no-empty-class": 2,
|
||||
"no-empty-label": 2,
|
||||
"no-eq-null": 0,
|
||||
"no-eval": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-bind": 2,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-semi": 2,
|
||||
"no-fallthrough": 2,
|
||||
"no-floating-decimal": 0,
|
||||
"no-func-assign": 2,
|
||||
"no-implied-eval": 2,
|
||||
"no-inline-comments": 0,
|
||||
"no-inner-declarations": [2, "functions"],
|
||||
"no-invalid-regexp": 2,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-iterator": 2,
|
||||
"no-label-var": 2,
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-lonely-if": 0,
|
||||
"no-loop-func": 2,
|
||||
"no-mixed-requires": [0, false],
|
||||
"no-mixed-spaces-and-tabs": [2, false],
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-multiple-empty-lines": [0, {"max": 2}],
|
||||
"no-native-reassign": 2,
|
||||
"no-negated-in-lhs": 2,
|
||||
"no-nested-ternary": 0,
|
||||
"no-new": 2,
|
||||
"no-new-func": 2,
|
||||
"no-new-object": 2,
|
||||
"no-new-require": 0,
|
||||
"no-new-wrappers": 2,
|
||||
"no-obj-calls": 2,
|
||||
"no-octal": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-path-concat": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-process-env": 0,
|
||||
"no-process-exit": 2,
|
||||
"no-proto": 2,
|
||||
"no-redeclare": 0,
|
||||
"no-regex-spaces": 2,
|
||||
"no-reserved-keys": 0,
|
||||
"no-restricted-modules": 0,
|
||||
"no-return-assign": 2,
|
||||
"no-script-url": 2,
|
||||
"no-self-compare": 0,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 2,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-spaced-func": 2,
|
||||
"no-sparse-arrays": 2,
|
||||
"no-sync": 0,
|
||||
"no-ternary": 0,
|
||||
"no-trailing-spaces": 0,
|
||||
"no-undef": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undefined": 2,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-unreachable": 2,
|
||||
"no-unused-expressions": 2,
|
||||
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
|
||||
"no-use-before-define": 2,
|
||||
"no-void": 0,
|
||||
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
|
||||
"no-with": 2,
|
||||
"no-wrap-func": 2,
|
||||
"block-scoped-var": 0,
|
||||
"brace-style": [0, "1tbs"],
|
||||
"camelcase": 0,
|
||||
"comma-spacing": 2,
|
||||
"comma-style": 0,
|
||||
"comma-dangle": [2, "never"],
|
||||
"complexity": [0, 11],
|
||||
"consistent-return": 2,
|
||||
"consistent-this": [0, "that"],
|
||||
"curly": [2, "all"],
|
||||
"default-case": 0,
|
||||
"dot-notation": 2,
|
||||
"eol-last": 0,
|
||||
"eqeqeq": 2,
|
||||
"func-names": 0,
|
||||
"func-style": [2, "expression"],
|
||||
"guard-for-in": 0,
|
||||
"handle-callback-err": 0,
|
||||
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
|
||||
"max-depth": [0, 4],
|
||||
"max-len": [0, 80, 4],
|
||||
"max-nested-callbacks": [0, 2],
|
||||
"max-params": [0, 3],
|
||||
"max-statements": [0, 10],
|
||||
"new-cap": 2,
|
||||
"new-parens": 2,
|
||||
"one-var": 0,
|
||||
"operator-assignment": [0, "always"],
|
||||
"padded-blocks": 0,
|
||||
"quote-props": 0,
|
||||
"quotes": [2, "single"],
|
||||
"radix": 0,
|
||||
"semi": 2,
|
||||
"sort-vars": 0,
|
||||
"space-after-keywords": [0, "always"],
|
||||
"space-before-blocks": [0, "always"],
|
||||
"space-in-brackets": [0, "never"],
|
||||
"space-in-parens": [0, "never"],
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"spaced-line-comment": [0, "always"],
|
||||
"strict": [2, "global"],
|
||||
"use-isnan": 2,
|
||||
"valid-jsdoc": 0,
|
||||
"valid-typeof": 2,
|
||||
"vars-on-top": 0,
|
||||
"wrap-iife": [2, "outside"],
|
||||
"wrap-regex": 0,
|
||||
"yoda": [2, "never"]
|
||||
}
|
||||
}
|
273
app.js
273
app.js
|
@ -15,38 +15,30 @@
|
|||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var url = require('url'),
|
||||
fs = require('fs'),
|
||||
port = process.env.PORT || 1337,
|
||||
request = require('request'),
|
||||
requester = require('./lib/requester.js'),
|
||||
express = require('express'),
|
||||
app = express(),
|
||||
bodyParser = require('body-parser'),
|
||||
cheerio = require('cheerio'),
|
||||
promises = require('promised-io/promise'),
|
||||
Deferred = require('promised-io').Deferred,
|
||||
promised = require("promised-io/promise"),
|
||||
promised = require('promised-io/promise'),
|
||||
bluebird = require('bluebird'),
|
||||
cssLoader = require('./lib/checks/loadcss.js'),
|
||||
jsLoader = require('./lib/checks/loadjs.js'),
|
||||
tests = require('./lib/checks/loadchecks.js').tests,
|
||||
http = require('http'),
|
||||
//http = require('http'),
|
||||
path = require('path'),
|
||||
zlib = require('zlib'),
|
||||
sanitize = require('validator').sanitize,
|
||||
charset = 'utf-8',
|
||||
querystring = require('querystring'),
|
||||
version = JSON.parse(fs.readFileSync('package.json')).version,
|
||||
request = request.defaults({followAllRedirects: true,
|
||||
encoding: null,
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept': 'text/html, application/xhtml+xml, */*',
|
||||
'Accept-Encoding': 'gzip,deflate',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)'}});
|
||||
version = JSON.parse(fs.readFileSync('package.json')).version;
|
||||
|
||||
/**
|
||||
* Serializes a test results array and sends it via the response
|
||||
|
@ -54,50 +46,57 @@ var url = require('url'),
|
|||
* @param {Timestamp} start The start timestamp
|
||||
* @param {Array} resultsArray The results of all the tests
|
||||
* */
|
||||
function sendResults(res, start, resultsArray) {
|
||||
var sendResults = function (res, start, resultsArray) {
|
||||
var results = {};
|
||||
|
||||
for (var i = 0; i < resultsArray.length; i++) {
|
||||
results[resultsArray[i].testName] = resultsArray[i];
|
||||
}
|
||||
res.writeHeader(200, {"Content-Type": "application/json",
|
||||
"X-Content-Type-Options": "nosniff" });
|
||||
res.write(JSON.stringify({version: version, url: {uri: (this && this.url && this.url.href) || 'http://private'}, processTime: (Date.now() - start)/1000, results: results}));
|
||||
res.writeHeader(200, {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Content-Type-Options': 'nosniff'
|
||||
});
|
||||
res.write(JSON.stringify({
|
||||
version: version,
|
||||
url: {uri: (this && this.url && this.url.href) || 'http://private'},
|
||||
processTime: (Date.now() - start) / 1000,
|
||||
results: results
|
||||
}));
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Responds with a bad request error
|
||||
* */
|
||||
function sendBadRequest(res){
|
||||
res.writeHeader(400, {"Content-Type": "text/plain"});
|
||||
var sendBadRequest = function (res) {
|
||||
res.writeHeader(400, {'Content-Type': 'text/plain'});
|
||||
res.write('Your package is malformed' + '\n');
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Responds with an internal server error
|
||||
* */
|
||||
function sendInternalServerError(error, res) {
|
||||
res.writeHeader(500, {"Content-Type": "text/plain"});
|
||||
var sendInternalServerError = function (error, res) {
|
||||
res.writeHeader(500, {'Content-Type': 'text/plain'});
|
||||
res.write(JSON.stringify(error) + '\n');
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Responds with the error and message passed as parameters
|
||||
* */
|
||||
function remoteErrorResponse(response, statusCode, message) {
|
||||
response.writeHead(200, {"Content-Type": "application/json"});
|
||||
var remoteErrorResponse = function (response, statusCode, message) {
|
||||
response.writeHead(200, {'Content-Type': 'application/json'});
|
||||
response.write(JSON.stringify({statusCode: statusCode, message: message}));
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Decompresses a byte array using the decompression method passed by type.
|
||||
* It supports gunzip and deflate
|
||||
* */
|
||||
function decompress(body, type) {
|
||||
var decompress = function (body, type) {
|
||||
var deferred = new Deferred();
|
||||
|
||||
if (type === 'gzip') {
|
||||
|
@ -116,7 +115,8 @@ function decompress(body, type) {
|
|||
if (!err) {
|
||||
deferred.resolve({
|
||||
body: data.toString(charset),
|
||||
compression: 'deflate'}
|
||||
compression: 'deflate'
|
||||
}
|
||||
);
|
||||
} else {
|
||||
deferred.reject('Error found: can\'t deflate content' + err);
|
||||
|
@ -124,39 +124,18 @@ function decompress(body, type) {
|
|||
});
|
||||
} else {
|
||||
process.nextTick(function () {
|
||||
deferred.reject("Unknown content encoding: " + type);
|
||||
deferred.reject('Unknown content encoding: ' + type);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the body of a pages and decompresses if needed
|
||||
* */
|
||||
function getBody(res, body) {
|
||||
var deferred = new Deferred();
|
||||
if (res.headers['content-encoding']) {
|
||||
return decompress(body, res.headers['content-encoding']);
|
||||
} else {
|
||||
process.nextTick(function () {
|
||||
if (body) {
|
||||
deferred.resolve({
|
||||
body: body.toString(charset),
|
||||
compression: 'none'});
|
||||
} else {
|
||||
deferred.reject('Error found: Empty body');
|
||||
}
|
||||
});
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Launches and returns an array with the promises of all the non parallel tests
|
||||
* (browser detection, css prefixes, etc.)
|
||||
* */
|
||||
function launchNonParallelTests(promisesArray, website) {
|
||||
var launchNonParallelTests = function (promisesArray, website) {
|
||||
var deferred = new Deferred();
|
||||
|
||||
process.nextTick(function () {
|
||||
|
@ -171,75 +150,108 @@ function launchNonParallelTests(promisesArray, website) {
|
|||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Since several tests need HTML/JS/CSS content, fetch it all at once
|
||||
* before calling any of the tests. Note that the tests still could
|
||||
* retrieve additional content async, since they return a promise.
|
||||
*/
|
||||
function analyze(data, content, res) {
|
||||
var start = Date.now(),
|
||||
promisesTests = [];
|
||||
// function analyze(data, content, res) {
|
||||
// var start = Date.now(),
|
||||
// promisesTests = [];
|
||||
|
||||
var website = {
|
||||
url: url.parse(data.uri),
|
||||
auth: data.auth,
|
||||
content: content.body,
|
||||
compression: content.compression,
|
||||
$: cheerio.load(content.body, { lowerCaseTags: true, lowerCaseAttributeNames: true })
|
||||
};
|
||||
// var website = {
|
||||
// url: url.parse(data.uri),
|
||||
// auth: data.auth,
|
||||
// content: content.body,
|
||||
// compression: content.compression,
|
||||
// $: cheerio.load(content.body, { lowerCaseTags: true, lowerCaseAttributeNames: true })
|
||||
// };
|
||||
|
||||
tests.forEach(function (test) {
|
||||
if (test.parallel) {
|
||||
promisesTests.push(test.check(website));
|
||||
// tests.forEach(function (test) {
|
||||
// if (test.parallel) {
|
||||
// promisesTests.push(test.check(website));
|
||||
// }
|
||||
// });
|
||||
|
||||
// cssLoader.loadCssFiles(website)
|
||||
// .then(jsLoader.loadjsFiles)
|
||||
// .then(launchNonParallelTests.bind(null, promisesTests))
|
||||
// .then(promises.all)
|
||||
// .then(sendResults.bind(website, res, start), sendInternalServerError.bind(website, res));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Gets the body of a pages and decompresses if needed
|
||||
* */
|
||||
var getBody = function (request, website) {
|
||||
//var deferred = new Deferred();
|
||||
console.log(website.url);
|
||||
return request.getAsync(website.url)
|
||||
.then(function (result) {
|
||||
var res = result[0];
|
||||
var body = result[1];
|
||||
|
||||
if(!body){
|
||||
return bluebird.reject('Error found: Empty body');
|
||||
}
|
||||
|
||||
website.url = url.parse(res.request.href); //In case there have been redirects
|
||||
if (res.headers['content-encoding']) {
|
||||
website.compression = res.headers['content-encoding'];
|
||||
}
|
||||
|
||||
website.content = body.toString(charset);
|
||||
website.$ = cheerio.load(website.content, {lowerCaseTags: true, lowerCaseAttributeNames: true});
|
||||
console.log('body loaded');
|
||||
return bluebird.resolve(website);
|
||||
});
|
||||
|
||||
cssLoader.loadCssFiles(website)
|
||||
.then(jsLoader.loadjsFiles)
|
||||
.then(launchNonParallelTests.bind(null, promisesTests))
|
||||
.then(promises.all)
|
||||
.then(sendResults.bind(website, res, start), sendInternalServerError.bind(website, res));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the request to get the body of a page and start all the process
|
||||
* */
|
||||
function processResponse(response, auth) {
|
||||
return function (err, res, body) {
|
||||
if (!err && res.statusCode === 200) {
|
||||
getBody(res, body)
|
||||
.then(function (result) {
|
||||
analyze({uri: res.request.href, auth: auth}, result, response);
|
||||
}, remoteErrorResponse.bind(null, response, res.statusCode));
|
||||
} else {
|
||||
remoteErrorResponse(response, res ? res.statusCode : 'No response', 'Error found: ' + err);
|
||||
}
|
||||
};
|
||||
}
|
||||
// function processResponse(response, auth) {
|
||||
// return function (err, res, body) {
|
||||
// if (!err && res.statusCode === 200) {
|
||||
// getBody(res, body)
|
||||
// .then(function (result) {
|
||||
// analyze({uri: res.request.href, auth: auth}, result, response);
|
||||
// }, remoteErrorResponse.bind(null, response, res.statusCode));
|
||||
// } else {
|
||||
// remoteErrorResponse(response, res ? res.statusCode : 'No response', 'Error found: ' + err);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the local scan page
|
||||
* */
|
||||
function returnMainPage(response) {
|
||||
fs.readFile(path.join(__dirname, "lib", "index.html"), function (err, data) {
|
||||
var returnMainPage = function (response) {
|
||||
fs.readFile(path.join(__dirname, 'lib', 'index.html'), function (err, data) {
|
||||
if (!err) {
|
||||
response.writeHeader(200, {"Content-Type": "text/html"});
|
||||
response.writeHeader(200, {'Content-Type': 'text/html'});
|
||||
|
||||
} else {
|
||||
response.writeHeader(500, {"Content-Type": "text/plain"});
|
||||
data = "Server error: " + err + "\n";
|
||||
response.writeHeader(500, {'Content-Type': 'text/plain'});
|
||||
data = 'Server error: ' + err + '\n';
|
||||
}
|
||||
response.write(data);
|
||||
response.end();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var getDomain = function (req, res) {
|
||||
res.writeHeader(200, {'Content-Type': 'text/plain'});
|
||||
res.write(process.env.USERDOMAIN || process.env.USERDNSDOMAIN);
|
||||
res.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* Decides what action needs to be done: show the main page or analyze a website
|
||||
* */
|
||||
function handleRequest(req, response) {
|
||||
var handleRequest = function (req, response) {
|
||||
if (req.url === '/') {
|
||||
// Return the "local scan" page
|
||||
returnMainPage(response);
|
||||
|
@ -251,29 +263,81 @@ function handleRequest(req, response) {
|
|||
urlToAnalyze = sanitize(decodeURIComponent(parameters.url)).xss(),
|
||||
user = sanitize(decodeURIComponent(parameters.user)).xss(),
|
||||
password = sanitize(decodeURIComponent(parameters.password)).xss(),
|
||||
domain = sanitize(decodeURIComponent(parameters.domain)).xss(),
|
||||
auth;
|
||||
|
||||
var website = {
|
||||
url: urlToAnalyze,
|
||||
auth: null, // We might not need this field
|
||||
$: null,
|
||||
content: '',
|
||||
compression: ''
|
||||
};
|
||||
|
||||
var request;
|
||||
|
||||
// If the request gave a user/pass, send it along. Wait for 401 response before sending passwords.
|
||||
if (user !== "undefined" && password !== "undefined") {
|
||||
if (user !== 'undefined' && password !== 'undefined') {
|
||||
auth = {
|
||||
'user': user,
|
||||
'pass': password,
|
||||
'sendImmediately': false
|
||||
};
|
||||
request(urlToAnalyze,
|
||||
{auth: auth},
|
||||
processResponse(response, auth));
|
||||
|
||||
request = requester(auth);
|
||||
website.auth = auth;
|
||||
// request(urlToAnalyze,
|
||||
// {auth: auth},
|
||||
// processResponse(response, auth));
|
||||
} else {
|
||||
request(urlToAnalyze, processResponse(response));
|
||||
request = requester();
|
||||
}
|
||||
|
||||
website.request = request;
|
||||
|
||||
var start = Date.now(),
|
||||
promisesTests = [];
|
||||
|
||||
tests.forEach(function (test) {
|
||||
if (test.parallel) {
|
||||
promisesTests.push(test.check(website));
|
||||
}
|
||||
});
|
||||
|
||||
getBody(request, website)
|
||||
.then(function (web) {
|
||||
console.log('CSSLoader');
|
||||
return cssLoader.loadCssFiles(web);
|
||||
})
|
||||
.then(function (web) {
|
||||
console.log('JS loader');
|
||||
return jsLoader.loadjsFiles(web);
|
||||
})
|
||||
.then(launchNonParallelTests.bind(null, promisesTests))
|
||||
.then(promises.all)
|
||||
.then(function (results) {
|
||||
sendResults(response, start, results);
|
||||
}, function (error) {
|
||||
sendInternalServerError(error, response);
|
||||
});
|
||||
// request(urlToAnalyze, function(err, res, body){
|
||||
// if (!err && res.statusCode === 200) {
|
||||
// getBody(res, body)
|
||||
// .then(function (result) {
|
||||
// analyze({uri: res.request.href}, result, response);
|
||||
// }, remoteErrorResponse.bind(null, response, res.statusCode));
|
||||
// } else {
|
||||
// remoteErrorResponse(response, res ? res.statusCode : 'No response', 'Error found: ' + err);
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the content of a package sent via any of the plugins
|
||||
* */
|
||||
function handlePackage(req, res) {
|
||||
var handlePackage = function (req, res) {
|
||||
if (!req.body.js || !req.body.css || !req.body.html || !req.body.url) {
|
||||
remoteErrorResponse(res, 400, "Missing information");
|
||||
remoteErrorResponse(res, 400, 'Missing information');
|
||||
}
|
||||
var start = Date.now(),
|
||||
cssPromises = [],
|
||||
|
@ -282,7 +346,7 @@ function handlePackage(req, res) {
|
|||
//TODO: try/catch this
|
||||
try {
|
||||
website = {
|
||||
url: req.body.url ? url.parse(req.body.url.replace(/"/g, '')) : "http://privates.ite",
|
||||
url: req.body.url ? url.parse(req.body.url.replace(/"/g, '')) : 'http://privates.ite',
|
||||
content: req.body.html,
|
||||
css: null,
|
||||
js: JSON.parse(req.body.js),
|
||||
|
@ -316,7 +380,7 @@ function handlePackage(req, res) {
|
|||
promises.all(promisesTests)
|
||||
.then(sendResults.bind(null, res, start));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// ## CORS middleware
|
||||
//
|
||||
|
@ -327,7 +391,7 @@ var allowCrossDomain = function (req, res, next) {
|
|||
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
||||
|
||||
// intercept OPTIONS method
|
||||
if ('OPTIONS' == req.method) {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.send(204);
|
||||
}
|
||||
else {
|
||||
|
@ -338,6 +402,7 @@ app.use(allowCrossDomain);
|
|||
|
||||
app.use(bodyParser.json());
|
||||
app.get('/', handleRequest);
|
||||
app.get('/domain', getDomain);
|
||||
app.post('/package', handlePackage);
|
||||
app.listen(port);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
var Deferred = require('promised-io').Deferred,
|
||||
Promise = require('promised-io/promise'),
|
||||
request = require('request'),
|
||||
// request = require('request'),
|
||||
rules = [
|
||||
"navigator.userAgent",
|
||||
"navigator.appVersion",
|
||||
|
@ -43,13 +43,13 @@ var Deferred = require('promised-io').Deferred,
|
|||
"protoaculous"
|
||||
];
|
||||
|
||||
request = request.defaults({
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)'}
|
||||
});
|
||||
// request = request.defaults({
|
||||
// jar: false,
|
||||
// proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
// headers: {
|
||||
// 'Accept-Language': 'en-US,en;q=0.5',
|
||||
// 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)'}
|
||||
// });
|
||||
|
||||
function checkScript(script) {
|
||||
var deferred = new Deferred();
|
||||
|
|
|
@ -87,7 +87,7 @@ var libraries = [
|
|||
minVersions: [
|
||||
{ major: "1.2.", minor: "6" },
|
||||
{ major: "1.4.", minor: "5" },
|
||||
{ major: "1.5.", minor: "" }
|
||||
{ major: "1.5.", minor: "1" }
|
||||
],
|
||||
check: function (scriptText) {
|
||||
var version = scriptText.match(/this.MooTools\s*=\s*\{version:\s*'(\d+\.\d+\.\d+)/m);
|
||||
|
@ -107,7 +107,7 @@ var libraries = [
|
|||
{
|
||||
name: "jQuery Form Plugin",
|
||||
minVersions: [
|
||||
{ major: "3.", minor: "22" }
|
||||
{ major: "3.", minor: "51" }
|
||||
],
|
||||
check: function (scriptText) {
|
||||
var version = scriptText.match(/Form Plugin\s+\*\s+version: (\d+\.\d+)/m);
|
||||
|
@ -119,7 +119,8 @@ var libraries = [
|
|||
minVersions: [
|
||||
{ major: "2.5.", minor: "2" },
|
||||
{ major: "2.6.", minor: "2" },
|
||||
{ major: "2.7.", minor: "1" }
|
||||
{ major: "2.7.", minor: "2" },
|
||||
{ major: "2.8.", minor: "3" }
|
||||
],
|
||||
check: function (scriptText) {
|
||||
// Static analysis. :( The version is set as a local variable, far from
|
||||
|
|
|
@ -16,59 +16,62 @@
|
|||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var request = require('request'),
|
||||
CSSLintRules = ['auto-imports'],
|
||||
var CSSLintRules = ['auto-imports'],
|
||||
CSSLint = require('./csslint.js').CSSLint,
|
||||
promised = require("promised-io/promise"),
|
||||
Deferred = require('promised-io').Deferred,
|
||||
bluebird = require('bluebird'),
|
||||
url = require('url'),
|
||||
cssPromises;
|
||||
|
||||
request = request.defaults({
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)'}});
|
||||
// parseCSS and parseCSSfromUrl call each other so we tell eslint to cool it
|
||||
/*eslint-disable no-use-before-define */
|
||||
|
||||
// parseCSS and parseCSSfromUrl call each other so we tell jshint to cool it
|
||||
/*jshint latedef: false*/
|
||||
var parseCSS = function (text, cssUrl, media, isInline, website) {
|
||||
var report,
|
||||
imports = [];
|
||||
|
||||
function parseCSSfromUrl(cssUrl, media, website) {
|
||||
var deferred = new Deferred(),
|
||||
params = {
|
||||
uri: cssUrl,
|
||||
headers: {'Accept': 'text/html, application/xhtml+xml, */*'}
|
||||
},
|
||||
auth = website.auth;
|
||||
if (auth) {
|
||||
params.auth = auth;
|
||||
report = CSSLint.verify(text);
|
||||
imports.push({cssUrl: isInline ? 'embed' : cssUrl, media: media, cssBody: text, report: report});
|
||||
report.messages.forEach(function (result) {
|
||||
if (CSSLintRules.indexOf(result.rule.id) !== -1) {
|
||||
result.message.forEach(function (cssImport) {
|
||||
//resolve url here
|
||||
var importUrl = url.resolve(cssUrl, cssImport.url);
|
||||
if (website.cssParsedUrls.indexOf(importUrl) === -1) {
|
||||
imports.push(parseCSSfromUrl(importUrl, cssImport.media, website));
|
||||
}
|
||||
|
||||
website.cssParsedUrls.push(cssUrl);
|
||||
request(params, function (error, response, body) {
|
||||
if (!error && response.statusCode === 200) {
|
||||
parseCSS(body, cssUrl, media, false, website).then(function (results) {
|
||||
deferred.resolve(results);
|
||||
});
|
||||
} else {
|
||||
console.warn("Request for " + cssUrl + " returned " + error);
|
||||
// Silently skip the troublesome file
|
||||
deferred.resolve([]);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
return bluebird.all(imports).then(function (results) {
|
||||
// Results may be different because @imports may have @imported other files (ad nauseum);
|
||||
// the .concat() will flatten one level of nested arrays which is all we need
|
||||
return bluebird.resolve([].concat.apply([], results));
|
||||
});
|
||||
};
|
||||
|
||||
var parseCSSfromUrl = function (cssUrl, media, website) {
|
||||
console.log(cssUrl);
|
||||
website.cssParsedUrls.push(cssUrl);
|
||||
return website.request.getAsync(cssUrl)
|
||||
.then(function (result) {
|
||||
var body = result[1].toString('utf-8');
|
||||
return parseCSS(body, cssUrl, media, false, website);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.warn('Request for ' + cssUrl + ' returned ' + error);
|
||||
// Silently skip the troublesome file
|
||||
return bluebird.resolve([]);
|
||||
});
|
||||
};
|
||||
|
||||
CSSLint.addRule({
|
||||
id: "auto-imports",
|
||||
name: "auto imports",
|
||||
desc: "downloads css imports",
|
||||
browsers: "All",
|
||||
id: 'auto-imports',
|
||||
name: 'auto imports',
|
||||
desc: 'downloads css imports',
|
||||
browsers: 'All',
|
||||
init: function (parser, reporter) {
|
||||
var rule = this,
|
||||
localImports = [];
|
||||
|
@ -92,41 +95,8 @@ CSSLint.addRule({
|
|||
}
|
||||
});
|
||||
|
||||
function parseCSS(text, cssUrl, media, isInline, website) {
|
||||
var report,
|
||||
deferred = new Deferred(),
|
||||
imports = [];
|
||||
//
|
||||
// auth = website.auth;
|
||||
|
||||
process.nextTick(function () {
|
||||
report = CSSLint.verify(text);
|
||||
imports.push({cssUrl: isInline ? "embed" : cssUrl, media: media, cssBody: text, report: report});
|
||||
report.messages.forEach(function (result) {
|
||||
if(CSSLintRules.indexOf(result.rule.id) !== -1){
|
||||
result.message.forEach(function(cssImport){
|
||||
//resolve url here
|
||||
var importUrl = url.resolve(cssUrl, cssImport.url);
|
||||
if (website.cssParsedUrls.indexOf(importUrl) === -1) {
|
||||
imports.push(parseCSSfromUrl(importUrl, cssImport.media, website));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
promised.all(imports).then(function (results) {
|
||||
// Results may be different because @imports may have @imported other files (ad nauseum);
|
||||
// the .concat() will flatten one level of nested arrays which is all we need
|
||||
deferred.resolve([].concat.apply([], results));
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function check(website) {
|
||||
var deferred = new Deferred(),
|
||||
cssLinks = website.$('link[rel="stylesheet"]'),
|
||||
var check = function (website) {
|
||||
var cssLinks = website.$('link[rel="stylesheet"]'),
|
||||
cssHref,
|
||||
cssUrl,
|
||||
cssTags;
|
||||
|
@ -155,23 +125,17 @@ function check(website) {
|
|||
}
|
||||
|
||||
if (cssPromises.length > 0) {
|
||||
promised.all(cssPromises).then(function (array) {
|
||||
return bluebird.all(cssPromises).then(function (array) {
|
||||
// Flatten the nested arrays
|
||||
array = [].concat.apply([], array);
|
||||
website.css = array;
|
||||
deferred.resolve(website);
|
||||
}, function () {
|
||||
deferred.reject();
|
||||
return bluebird.resolve(website);
|
||||
});
|
||||
} else {
|
||||
// No style sheets
|
||||
process.nextTick(function(){
|
||||
deferred.resolve(website);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return bluebird.resolve(website);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports.parseCSS = parseCSS;
|
||||
|
|
|
@ -16,47 +16,23 @@
|
|||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var request = require('request'),
|
||||
promised = require("promised-io/promise"),
|
||||
Deferred = require('promised-io').Deferred,
|
||||
var bluebird = require('bluebird'),
|
||||
url = require('url');
|
||||
|
||||
request = request.defaults({
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)'}});
|
||||
|
||||
function downloadJS(jsUrl, jsHref, auth) {
|
||||
var jsDeferred = new Deferred(),
|
||||
parameters = {uri: jsUrl,
|
||||
headers: {
|
||||
'Accept': 'text/html, application/xhtml+xml, */*'}};
|
||||
|
||||
if (auth) {
|
||||
parameters.auth = auth;
|
||||
}
|
||||
|
||||
request(parameters, function (error, response, body) {
|
||||
if (!error && response.statusCode === 200) {
|
||||
response.on('error', function (e) {
|
||||
console.log('loading CSS' + e);
|
||||
});
|
||||
jsDeferred.resolve({url: url, jsUrl: jsHref, finalUrl: response.request.href, content: body});
|
||||
} else {
|
||||
jsDeferred.resolve({});
|
||||
}
|
||||
var downloadJS = function (jsUrl, jsHref, website) {
|
||||
console.log(jsUrl);
|
||||
return website.request.getAsync(jsUrl)
|
||||
.then(function (result) {
|
||||
var response = result[0];
|
||||
var body = result[1].toString('utf-8');
|
||||
return bluebird.resolve({url: url, jsUrl: jsHref, finalUrl: response.request.href, content: body});
|
||||
});
|
||||
};
|
||||
|
||||
return jsDeferred.promise;
|
||||
}
|
||||
|
||||
function check(website) {
|
||||
var deferred = new Deferred(),
|
||||
jsLinks = website.$('script'),
|
||||
var check = function (website) {
|
||||
var jsLinks = website.$('script'),
|
||||
js = [],
|
||||
jsPromises = [];
|
||||
|
||||
|
@ -69,7 +45,7 @@ function check(website) {
|
|||
if (jsHref) {
|
||||
if (jsHref) {
|
||||
jsUrl = url.resolve(website.url, jsHref);
|
||||
jsPromises.push(downloadJS(jsUrl, jsHref, website.auth));
|
||||
jsPromises.push(downloadJS(jsUrl, jsHref, website));
|
||||
}
|
||||
} else if (jsLinks[i].children[0] && jsLinks[i].children[0].data) {
|
||||
// Some <script> tags that do not contain anything. We ignore those
|
||||
|
@ -78,7 +54,8 @@ function check(website) {
|
|||
}
|
||||
|
||||
if (jsPromises.length > 0) {
|
||||
promised.all(jsPromises).then(function (array) {
|
||||
return bluebird.all(jsPromises)
|
||||
.then(function (array) {
|
||||
for (i = 0; i < array.length; i++) {
|
||||
if (array[i].finalUrl) {
|
||||
js.push(array[i]);
|
||||
|
@ -87,19 +64,13 @@ function check(website) {
|
|||
|
||||
website.js = js;
|
||||
|
||||
deferred.resolve(website);
|
||||
}, function () {
|
||||
deferred.reject();
|
||||
return bluebird.resolve(website);
|
||||
});
|
||||
} else {
|
||||
// There aren't any external JS but we could have embedded JS
|
||||
process.nextTick(function(){
|
||||
website.js = js;
|
||||
deferred.resolve(website);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return bluebird.resolve(website);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.loadjsFiles = check;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
'use strict';
|
||||
|
||||
var request = require('request'),
|
||||
httpntlm = require('httpntlm'),
|
||||
http = require('http'),
|
||||
bluebird = require('bluebird');
|
||||
|
||||
var internalRequest = request.defaults({
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'
|
||||
}
|
||||
});
|
||||
|
||||
var authInfos = {
|
||||
type: "none",
|
||||
username: "",
|
||||
password: "",
|
||||
domain: "",
|
||||
};
|
||||
|
||||
// ## HTTP Headers lowercase error
|
||||
//
|
||||
// see: http://stackoverflow.com/questions/20643699/how-do-i-send-uppercase-headers-in-http
|
||||
var automaticHeaders = {
|
||||
connection: true,
|
||||
'content-length': true,
|
||||
'transfer-encoding': true,
|
||||
date: true
|
||||
};
|
||||
http.OutgoingMessage.prototype.setHeader = function (name, value) {
|
||||
if (arguments.length < 2) {
|
||||
throw new Error('`name` and `value` are required for setHeader().');
|
||||
}
|
||||
|
||||
if (this._header) {
|
||||
throw new Error('Can\'t set headers after they are sent.');
|
||||
}
|
||||
|
||||
// NO LOWER CASE
|
||||
var key = name;//.toLowerCase();
|
||||
this._headers = this._headers || {};
|
||||
this._headerNames = this._headerNames || {};
|
||||
this._headers[key] = value;
|
||||
this._headerNames[key] = name;
|
||||
|
||||
if (automaticHeaders[key]) {
|
||||
if (this._removedHeader) {
|
||||
this._removedHeader[key] = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = function(auth){
|
||||
if(!auth || auth.type !== 'ntlm') {
|
||||
var defaultRequest = request.defaults({
|
||||
followAllRedirects: true,
|
||||
encoding: null,
|
||||
auth: auth,
|
||||
gzip: true,
|
||||
jar: false,
|
||||
proxy: process.env.HTTP_PROXY || process.env.http_proxy,
|
||||
headers: {
|
||||
'Accept': 'text/html, application/xhtml+xml, */*',
|
||||
'Accept-Encoding': 'gzip,deflate',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko' /* Set IE11 UA */
|
||||
}
|
||||
});
|
||||
|
||||
return bluebird.promisifyAll(defaultRequest);
|
||||
}
|
||||
};
|
||||
|
||||
// exports.authInfos = authInfos;
|
||||
// exports.defaultRequest = defaultRequest;
|
||||
// exports.internalRequest = internalRequest;
|
|
@ -24,12 +24,14 @@
|
|||
"test": "grunt test"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "^2.9.30",
|
||||
"body-parser": "^1.13.1",
|
||||
"cheerio": "^0.19.0",
|
||||
"cssom": ">=0.2.5",
|
||||
"express": "^4.12.4",
|
||||
"httpntlm": "^1.5.2",
|
||||
"parserlib": "~0.2.3",
|
||||
"promised-io": ">=0.3.0",
|
||||
"promised-io": "^0.3.5",
|
||||
"request": "^2.58.0",
|
||||
"validator": "~0.4.22",
|
||||
"xml2js": ">=0.2.0",
|
||||
|
|
Загрузка…
Ссылка в новой задаче