/**
* @license Apache-2.0
* Copyright (C) 2016 The Sitecheck Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"use strict";
var winston = require("winston");
var Promise = require("bluebird");
var Target = require('./target.js');
var params = require('./params.js');
var CancellationToken = require('./cancellationToken.js');
const CONSTANTS = require("./constants.js");
var Issue = require('./issue.js');
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {
handleExceptions: true, humanReadableUnhandledException: true
});
var targets = [];
/**
* Main function.
* Starts a scan.
* @param {Array} opts - An array of scan parameters.
* <ul>
* <li>config : path to config file.</li>
* <li>url : Url to scan. Mandatory unless defined in config file.</li>
* <li>checks : An array of check names. Check names must match names of js files in src/checks/**, without ".js". Mandatory unless defined in config file.</li>
* <li>allPages : true to scan all pages of website. Default is false.</li>
* <li>log : true to activate log to file. Default is false.</li>
* <li>silent : true to prevent console logs. Default is false.</li>
* <li>loglevel : sets log level. Possible values are "error", "warn", " ", "verbose", "debug", "silly". Default is "warn".</li>
* </ul>
* @param {function} endCallback - (err, data). data is an array of Issue(s).
* @param {function} progressCallback - (data). data is an object :
* { progress : float 0.0 - 1.0,
* targetProgress : float 0.0 - 1.0,
* issues : [array os Issue],
* targets : [array of Target] }
*/
function scan(opts, endCallback, progressCallback) {
params.gatherScanParams(opts);
var scanId = "";
targets.push(new Target(params.url, CONSTANTS.TARGETTYPE.PAGE));
targets.push(new Target(params.url, CONSTANTS.TARGETTYPE.SERVER));
targets[1].isDone = true;
let index = 0;
var ct = new CancellationToken();
// check targets SERIALLY and call cb after each one.
Promise.mapSeries(targets, function (target, index, length) {
if (target.isDone)
return;
return checkTarget(target, ct, progressCallback, index, length);
}).then(function () {
endCallback();
}).catch(function (data) {
if (data instanceof Error) endCallback(data);
else endCallback(null, data);
});
}
function checkTarget(target, cancellationToken, progressCallback, targetIndex, targetCount) {
let runningChecks = [];
let checksCount = params.checks.length;
let checksDone = 0;
for (let checkName of params.checks) {
let fileName = params.checkMap.get(checkName);
let Check = require(fileName);
let check = new Check(target);
Eif (check.targetType == target.targetType) {
runningChecks.push(
check.check(cancellationToken).then(() => {
checksDone++;
let curTargetProgress = checksDone / checksCount;
let overallProgress = (targetIndex + checksProgress) / checksProgress;
let progressData = {
progress: targetsProgress,
targetProgress: curTargetProgress
}
progressCallback(progress);
console.log("yipikaï !");
}).catch((err) => {
checksDone++;
Eif (err) {
Iif (err instanceof Error) {
console.log('Check "' + fileName + '" aborted.');
} else Eif (err instanceof Array) {
for (let a of err) {
Eif (a instanceof Issue) {
let maybeFP = '';
Iif (a.maybeFalsepositive) maybeFP = " (may be false positive)";
console.log("Issue : " + a.ref + " : " + a.errorContent + maybeFP);
}
}
}
}
}));
}
}
// Concurrency level can be managed by request option "pool: {maxSockets: Infinity}" (https://github.com/request/request#requestoptions-callback)
return Promise.all(runningChecks);
}
module.exports = { scan: scan }; |