-
-
Notifications
You must be signed in to change notification settings - Fork 374
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(linter): create respec linter * feat(profile-w3c-common): add linter to plugins * chore(package): run jshint/jscs on linter.js * feat(linter): linter HTTP URLs in config (closes #814) * add findHTTPProps() method to linter * add logic to run() method re: findHTTPProps * style(linter-spec): fix typo
- Loading branch information
Marcos Cáceres
committed
Jul 14, 2016
1 parent
95cabd8
commit 10d2429
Showing
6 changed files
with
244 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
"use strict"; | ||
define(["core/pubsubhub"], function(pubsubhub) { | ||
/** | ||
* Checks for privacy and security and considerations heading. If "privacy" or | ||
* "security", and "considerations", in any order, case-insensitive, | ||
* multi-line check. | ||
* | ||
* @param {Document} doc The document to be checked. | ||
* @return {Boolean} Returns true if section is found. | ||
*/ | ||
function hasPriSecConsiderations(doc) { | ||
return Array | ||
.from(doc.querySelectorAll("h2, h3, h4, h5, h6")) | ||
.map(function(elem) { | ||
return elem.textContent; | ||
}) | ||
.some(function(text) { | ||
var privOrSecRegex = /(privacy|security)/igm; | ||
var considerationsRegex = /(considerations)/igm; | ||
return privOrSecRegex.test(text) && considerationsRegex.test(text); | ||
}); | ||
} | ||
|
||
function findHTTPProps(conf, base) { | ||
return Object.getOwnPropertyNames(conf) | ||
.filter(function(key) { | ||
return key.endsWith("URI") || key === "prevED"; | ||
}) | ||
.filter(function(key) { | ||
return new URL(conf[key], base).href.startsWith("http://"); | ||
}); | ||
} | ||
|
||
return { | ||
run: function(conf, doc, cb) { | ||
if (!conf.lint || conf.status === "unofficial") { | ||
return cb(); | ||
} | ||
var warnings = []; | ||
var warn = ""; | ||
|
||
// Warn if no privacy and/or security considerations section | ||
if (!hasPriSecConsiderations(doc)) { | ||
warn = "This specification doesn't appear to have any 'Privacy' " + | ||
" or 'Security' considerations sections. Please consider adding one" + | ||
", see https://w3ctag.github.io/security-questionnaire/"; | ||
warnings.push(warn); | ||
} | ||
|
||
// Warn about HTTP URLs used in respecConfig | ||
var httpURLs = findHTTPProps(conf, doc.location.href); | ||
if (httpURLs.length) { | ||
warn = "There are insecure URLs in your respecConfig! Please change " + | ||
"the following properties to use 'https://': " + httpURLs.join(", ") + "."; | ||
warnings.push(warn); | ||
} | ||
|
||
// Publish warnings | ||
warnings.map(function(warn) { | ||
pubsubhub.pub("warning", warn); | ||
}); | ||
|
||
cb(); | ||
}, | ||
// Convenience methods, for quickly testing rules. | ||
rules: { | ||
"findHTTPProps": findHTTPProps, | ||
"hasPriSecConsiderations": hasPriSecConsiderations, | ||
}, | ||
}; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
"use strict"; | ||
describe("W3C - Linter", function() { | ||
var linter; | ||
beforeAll(function(done) { | ||
require(["w3c/linter"], function(l) { | ||
linter = l; | ||
done(); | ||
}); | ||
}); | ||
describe("hasPriSecConsiderations", function() { | ||
it("ignores just privacy sections", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "the privacy of things"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
}); | ||
it("ignores just security sections", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "security of things"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
}); | ||
it("ignores just considerations sections", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "Considerations for other things"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
}); | ||
it("finds privacy considerations sections", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "Considerations of privacy of things"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
}); | ||
it("finds security considerations sections", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "Considerations of security of things"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
}); | ||
it("finds privacy and security considerations sections, irrespective of order", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
elem.innerHTML = "Privacy and Security Considerations"; | ||
doc.body.appendChild(elem); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "Security and Privacy Considerations"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "Considerations Security Privacy"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
}); | ||
it("finds privacy and security considerations case insensitive", function() { | ||
var doc = document.implementation.createHTMLDocument("test doc"); | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(false); | ||
var elem = doc.createElement("h2"); | ||
doc.body.appendChild(elem); | ||
elem.innerHTML = "Privacy and Security Considerations"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "Privacy and Security Considerations"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "PRIVACY and Security Considerations"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "PriVacy and SECURITY Considerations"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "PRIVACY AND SECURITY CONSIDERATIONS"; | ||
expect(linter.rules.hasPriSecConsiderations(doc)).toEqual(true); | ||
elem.innerHTML = "privacy considerations security"; | ||
}); | ||
}); | ||
describe("findHTTPProps", function() { | ||
it("checks any prop ending with 'URI' (case sensitive)", function() { | ||
var conf = { | ||
"FAIL_uri": "http://fail", | ||
"failURIfail": "http://fail", | ||
"URI": "http://pass", | ||
"charterDisclosureURI": "http://pass", | ||
"URI_FAIL": "http://fail", | ||
"uri_FAIL": "http://fail", | ||
}; | ||
var props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props).toEqual(jasmine.arrayContaining(["URI", "charterDisclosureURI"])); | ||
conf.charterDisclosureURI = "https://valid"; | ||
conf.URI = "https://valid"; | ||
props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props.length).toEqual(0); | ||
}); | ||
it("checks for prevED, as special case", function() { | ||
var conf = { | ||
"FAIL_uri": "http://fail", | ||
"failURIfail": "http://fail", | ||
"prevED": "http://pass", | ||
"charterDisclosureURI": "http://pass", | ||
"URI_FAIL": "http://fail", | ||
}; | ||
var props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props).toEqual(jasmine.arrayContaining(["prevED", "charterDisclosureURI"])); | ||
conf.prevED = "https://valid-now"; | ||
props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props).toEqual(jasmine.arrayContaining(["charterDisclosureURI"])); | ||
}); | ||
it("flags well-known props as invalid, when invalid URLs are present", function() { | ||
var conf = { | ||
charterDisclosureURI: "http://invalid", | ||
edDraftURI: "http://invalid", | ||
implementationReportURI: "http://invalid", | ||
previousDiffURI: "http://invalid", | ||
previousMaturityURI: "http://invalid", | ||
previousURI: "http://invalid", | ||
prevRecURI: "http://invalid", | ||
testSuiteURI: "http://invalid", | ||
wgPatentURI: "http://invalid", | ||
wgURI: "http://invalid", | ||
}; | ||
var props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props).toEqual(jasmine.arrayContaining([ | ||
"charterDisclosureURI", | ||
"edDraftURI", | ||
"implementationReportURI", | ||
"previousDiffURI", | ||
"previousMaturityURI", | ||
"previousURI", | ||
"prevRecURI", | ||
"testSuiteURI", | ||
"wgPatentURI", | ||
"wgURI", | ||
])); | ||
}); | ||
it("ignores well-known URIs when they are valid", function() { | ||
var conf = { | ||
charterDisclosureURI: "https://valid.com", | ||
edDraftURI: "https://valid.net", | ||
implementationReportURI: "https://valid.org", | ||
previousDiffURI: "https://valid.net", | ||
previousMaturityURI: "https://valid.org", | ||
previousURI: "https://valid.com", | ||
prevRecURI: "https://valid.example", | ||
testSuiteURI: "https://valid.baz", | ||
wgPatentURI: "https://valid.bar", | ||
wgURI: "https://valid.com", | ||
}; | ||
var props = linter.rules.findHTTPProps(conf, document.location.href); | ||
expect(props.length).toEqual(0); | ||
}); | ||
it("lints URLs by resolving them as real URLs", function() { | ||
var conf = { | ||
"someRelativeURI": "./foo/bar", | ||
"somePathURI": "/foo/bar", | ||
"someControlURI": "https://valid", | ||
}; | ||
var props = linter.rules.findHTTPProps(conf, "http://invalid"); | ||
expect(props).toEqual(jasmine.arrayContaining(["someRelativeURI", "somePathURI"])); | ||
conf.someControlURI = "http://invalid"; | ||
props = linter.rules.findHTTPProps(conf, "http://valid"); | ||
expect(props).toEqual(jasmine.arrayContaining(["someControlURI"])); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters