Merge pull request #98 from m-gagne/master

Fixes for #95, #97 & #99
This commit is contained in:
Anton Molleda 2015-08-29 11:07:56 -07:00
Родитель a7bafb1f8a cce7ccf520
Коммит 45bba60dca
25 изменённых файлов: 2452 добавлений и 185 удалений

Просмотреть файл

@ -19,11 +19,8 @@ module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
nodeunit: {
all: ['test/**/*.js'],
libs: ['test/**/checklibs*.js'],
compat: ['test/**/compatlist*.js'],
cssprefixes: ['test/**/cssprefixes*.js'],
doctype: ['test/**/doctype*.js'],
ie11tiles: ['test/**/ie11*.js'],
pluginfree: ['test/**/pluginfree*.js'],
rwd: ['test/**/responsive*.js'],
@ -32,7 +29,6 @@ module.exports = function (grunt) {
input: ['test/**/input*.js'],
browserdetection: ['test/**/browserdetection*.js'],
preload: ['test/**/pre*.js'],
auth: ['test/**/auth*.js'],
altImg: ['test/**/alt*.js'],
aria: ['test/**/aria*.js']
},
@ -67,7 +63,6 @@ module.exports = function (grunt) {
}
});
grunt.loadNpmTasks('grunt-contrib-nodeunit');
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-jshint");
// Default task.
grunt.registerTask('default', ['jshint', 'nodeunit']);

Просмотреть файл

@ -20,19 +20,38 @@
var bluebird = require('bluebird');
var check = bluebird.method(function (website) {
var passed = true,
images = website.$('img:not([alt])'),
l = images.length,
filtered = [];
if (images.length > 0) {
passed = false;
for (var i = 0; i < l; i++) {
var src = images[i].attribs.src;
if (filtered.indexOf(src) === -1) {
filtered.push(images[i].attribs.src);
var passed = true,
filtered = [];
var testImages = function (images, filtered) {
var passed = true;
var l = images.length;
if (l > 0) {
passed = false;
for (var i = 0; i < l; i++) {
var src = images[i].attribs.src;
if (filtered.indexOf(src) === -1) {
filtered.push(images[i].attribs.src);
}
}
}
return passed;
}
// Check for missing alt attribute
// Example: <img src="" />
// Test: static/altImg-3.html
passed = testImages(website.$('img:not([alt])'), filtered);
// Check for empty alt attribute
// Example: <img src="" alt="" />
// Test: static/altImg-2.htm
if (passed) {
passed = testImages(website.$('img[alt=""]'), filtered);
}
var test = {

Просмотреть файл

@ -86,8 +86,6 @@ var checkConfigFile = bluebird.method(function (website) {
if (configTag.length > 0) {
url = website.url.resolve($(configTag[0]).attr('content'));
} else {
url = website.url.resolve('/browserconfig.xml');
}
return website.request.getAsync(url)

Просмотреть файл

@ -281,7 +281,7 @@ var libraries = [
}
//If header fails, we look with another pattern
var regex = /(?:jquery[,\)].*=")(\d+\.\d+)(\..*?)"/gi;
var regex = /(?:jquery[,\)].{0,200}=")(\d+\.\d+)(\..*?)"/gi;
var results = regex.exec(scriptText);
version = results ? (results[1] + (results[2] || '')) : null;

Просмотреть файл

@ -107,7 +107,6 @@ var downloadCVlists = function () {
return bluebird.all(requests)
.then(function () {
console.log('CV list downloaded');
return cvlist;
})
.catch(function (err) {
@ -120,15 +119,15 @@ var downloadCVlists = function () {
//.then(saveCVList);
};
downloadCVlists();
setInterval(downloadCVlists, 3600000); //We are not persisting the file anymore in file, refresh every hour
var getList = bluebird.method(function () {
//TODO: There will be a small lapse of time where the cvlist will be empty, need to fix that
if (typeof cvlist === 'object' && Object.keys(cvlist).length > 0) {
return cvlist;
}
// cv list has not been populated, download now and return promise
return downloadCVlists();
});
module.exports.getList = getList;

Просмотреть файл

@ -53,7 +53,6 @@ var parseCSS = function (text, cssUrl, media, isInline, website) {
};
var parseCSSfromUrl = function (cssUrl, media, website) {
console.log(cssUrl);
website.cssParsedUrls.push(cssUrl);
return website.request.getAsync(cssUrl)
.then(function (result) {

Просмотреть файл

@ -22,7 +22,6 @@ var bluebird = require('bluebird'),
url = require('url');
var downloadJS = function (jsUrl, jsHref, website) {
console.log(jsUrl);
return website.request.getAsync(jsUrl)
.then(function (result) {
var response = result[0];

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="Auth 1" content="Basic Auth">
</head>
<body>
<h1>Simple page with basic auth</h1>
<p>Expected result: <b>Passes</b></p>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="Auth 2" content="Basic Auth - 2">
<script src="/js/jquery-1.4.2.min.js"></script>
</head>
<body>
<h1>Page with resources and basic auth</h1>
<p>Expected result: <b>Fails js version</b></p>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="Auth 3" content="Basic Auth - 3">
<link rel="stylesheet" href="css/msTouch.css" />
</head>
<body>
<h1>Page with resources and basic auth</h1>
<p>Expected result: <b>Passes Touch</b></p>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="Auth 4" content="Basic Auth - 4">
<script src="/js/jquery-1.4.2.min.js"></script>
<link rel="stylesheet" href="css/msTouch.css" />
</head>
<body>
<h1>Page with resources and basic auth</h1>
<p>Expected result: <b>Passes Touch, fails js libs</b></p>
</body>
</html>

Просмотреть файл

@ -1,34 +0,0 @@
/**
* Description: Test that local scans can use authenticated (user/password) pages.
* At the moment, only supports Basic and Digest auth courtesy of node.js request.
*
* Copyright (c) Microsoft Corporation; All rights reserved.
*
* 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
*
* THIS CODE IS PROVIDED AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS
* OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions
* and limitations under the License.
*/
"use strict";
var express = require('express'),
app = express(),
port = process.env.PORT || 1000;
// Authenticator
app.use(express.basicAuth(function (user, pass) {
return user === "user" && pass === "password";
}));
app.use("/", express.static(__dirname + "/"));
app.listen(port);
module.exports.port = port;

2363
static/js/bootstrap-3.3.5.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

7
static/js/bootstrap-3.3.5.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

6
static/js/jquery-1.11.3.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

15
static/libs-12.html Normal file
Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="Bootstrap 3.3.4">
<script src="js/bootstrap-3.3.5.js"></script>
<script src="js/bootstrap-3.3.5.min.js"></script>
</head>
<body>
<h1>Bootstrap (compiled & minified)</h1>
<p>Expected result: <b>Passes</b></p>
</body>
</html>

Просмотреть файл

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title></title>
<meta name="description" content="jQuery & Dojo up to date">
<script src="js/jquery-1.11.1.min.js"></script>
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/dojo-1.9.2.js"></script>
</head>
<body>

Просмотреть файл

@ -20,7 +20,7 @@ http.createServer(function(req, res) {
var filename = path.join(process.cwd(),'static', uri);
fs.exists(filename, function(exists) {
if(!exists) {
console.log("not exists: " + filename);
console.error("not exists: " + filename);
res.writeHead(404, {'Content-Type': 'text/plain'});
res.write('404 Not Found\n');
res.end();

Просмотреть файл

@ -1,76 +0,0 @@
/**
* Description: Test that local scans can use authenticated (user/password) pages.
* At the moment, only supports Basic and Digest auth courtesy of node.js request.
*
* Copyright (c) Microsoft Corporation; All rights reserved.
*
* 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
*
* THIS CODE IS PROVIDED AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS
* OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions
* and limitations under the License.
*/
"use strict";
var service = require('../app.js'),
serviceUrl = 'http://localhost:' + service.port + '/?url=%0',
authString = '&user=%1&password=%2',
authServer = require('../static/auth-server.js'),
serverUrl = 'http%3A%2F%2Flocalhost%3A' + authServer.port + '%2Fauth-',
request = require('request');
function checkObject(object, expected, test) {
for (var key in expected) {
if (typeof expected[key] === "object") {
checkObject(object[key], expected[key], test);
} else {
test.equal(object[key], expected[key], object[key] + " !== " + expected[key]);
}
}
}
function deepCount(object){
var count = 0;
if(typeof object === "object"){
for(var key in object){
count += deepCount(object[key]);
}
}else{
count++;
}
return count;
}
function checkPage(page, expected, auth) {
return function (test) {
var uri = page.indexOf('http') === 0 ? page : serviceUrl.replace('%0', serverUrl + page),
tests = deepCount(expected);
if (auth) {
uri += authString.replace('%1', auth.user).replace('%2', auth.password);
}
test.expect(tests);
request(uri, function (error, response, content) {
var result = JSON.parse(content);
checkObject(result, expected, test);
test.done();
});
};
}
module.exports['Auth Tests'] = {
'No auth': checkPage('1.html', {statusCode: 401}),
'Basic auth': checkPage('1.html', {results: {cvlist: {passed: true}}}, {user: 'user', password: 'password'}),
'Basic auth - failing JS': checkPage('2.html', {results: {jslibs: {passed: false}}}, {user: 'user', password: 'password'}),
'Basic auth - touch': checkPage('3.html', {results: {touch: {passed: true}}}, {user: 'user', password: 'password'}),
'Basic auth - failing JS, touch': checkPage('4.html', {results: {jslibs: {passed: false}, touch: {passed: true}}}, {user: 'user', password: 'password'})
};

Просмотреть файл

@ -23,6 +23,7 @@ var checklibs = require('../lib/checks/check-libs.js'),
cheerio = require('cheerio'),
jsloader = require('../lib/loadjs.js'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/libs-';
@ -42,6 +43,7 @@ function checkPage(page, test, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content)
};
@ -161,5 +163,13 @@ module.exports['JS Libraries'] = {
}
]
});
}
},
// Unit test for issue #97 (https://github.com/MicrosoftEdge/static-code-scan/issues/97)
// Tests both compiled & minified version of Bootstrap 3.3.5 which previously caused a
// false negative scan (detected as out dated jQuery)
'Boostrap 3.3.5': function (test) {
checkPage('12.html', test, {
passed: true
});
}
};

Просмотреть файл

@ -23,6 +23,7 @@ var cssprefixes = require('../lib/checks/check-cssprefixes.js'),
request = require('request'),
cheerio = require('cheerio'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/cssprefixes-';
@ -43,6 +44,7 @@ function checkPage(page, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content)
};

Просмотреть файл

@ -22,6 +22,7 @@ var ie10fav = require('../lib/checks/check-ie11tiles.js'),
request = require('request'),
cheerio = require('cheerio'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/ie11tiles-';
@ -41,6 +42,7 @@ function checkPage(page, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content)
};

Просмотреть файл

@ -22,6 +22,7 @@ var pluginChecker = require('../lib/checks/check-pluginfree.js'),
cheerio = require('cheerio'),
url = require('url'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/plugin-';
@ -40,6 +41,7 @@ function checkPage(page, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content, { lowerCaseTags: true, lowerCaseAttributeNames: true })
};
@ -85,10 +87,15 @@ module.exports['Plugin Free'] = {
lineNumber: 11
}
}),
/*
* REMOVED BY M-GAGNE
* aardman.com no longer in CV List
* this test is fragile as the CV List changes
'Blocked website in CV List': checkPage('http://aardman.com',{passed:false,
data:{
activex: false,
cvlist: true
}}),
*/
'Embed tag with SVG instead flash ( http://doulosdiscovery.org)': checkPage('http://doulosdiscovery.org', {passed: true})
};

Просмотреть файл

@ -23,6 +23,7 @@ var responsive = require('../lib/checks/check-responsive.js'),
request = require('request'),
cheerio = require('cheerio'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/rwd-';
@ -43,6 +44,7 @@ function checkPage(page, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content)
};

Просмотреть файл

@ -24,6 +24,7 @@ var touchChecker = require('../lib/checks/check-touch.js'),
request = require('request'),
cheerio = require('cheerio'),
testServer = require('../static/test-server.js'),
requester = require('../lib/requester.js'),
testUrl = 'http://localhost:' + testServer.port + '/touch-';
@ -44,6 +45,7 @@ function checkPage(page, expected) {
var website = {
url: url.parse(uri),
content: content,
request: requester(),
$: cheerio.load(content)
};