Skip to content

Commit

Permalink
Merge pull request uswds#4329 from uswds/gsq-xss-audit
Browse files Browse the repository at this point in the history
USWDS | xss audit, standardization
  • Loading branch information
thisisdano authored Oct 25, 2021
2 parents 2d5b4b3 + ff30ee4 commit 36b25d6
Show file tree
Hide file tree
Showing 33 changed files with 720 additions and 479 deletions.
10 changes: 10 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ extends:
- prettier
plugins:
- import
- no-unsanitized
env:
node: true
browser: true
Expand All @@ -11,3 +12,12 @@ rules:
import/no-extraneous-dependencies:
- error
- devDependencies: true
no-unsanitized/method: error
no-unsanitized/property: error
overrides:
- { files: ['*.spec.js'],
rules: {
no-unsanitized/method: off,
no-unsanitized/property: off
}
}
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.24.0",
"eslint-plugin-no-unsanitized": "^3.1.5",
"fancy-log": "^1.3.3",
"gulp": "^4.0.2",
"gulp-changed": "^4.0.3",
Expand Down
6 changes: 6 additions & 0 deletions spec/unit/character-count/character-count.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,10 @@ describe("character count component", () => {
assert.strictEqual(input.validationMessage, VALIDATION_MESSAGE);
assert.strictEqual(message.classList.contains(MESSAGE_INVALID_CLASS), true);
});

it("should not allow for innerHTML of child elements ", () => {
Array.from(message.childNodes).forEach((childNode) => {
assert.strictEqual(childNode.nodeType, Node.TEXT_NODE);
});
});
});
21 changes: 12 additions & 9 deletions spec/unit/character-count/invalid-template-no-message.spec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const CharacterCount = require('../../../src/js/components/character-count');
const fs = require("fs");
const path = require("path");
const assert = require("assert");
const CharacterCount = require("../../../src/js/components/character-count");

const INVALID_TEMPLATE_NO_MESSAGE = fs.readFileSync(path.join(__dirname, '/invalid-template-no-message.template.html'));
const INVALID_TEMPLATE_NO_MESSAGE = fs.readFileSync(
path.join(__dirname, "/invalid-template-no-message.template.html")
);

describe('character count component without message', () => {
describe("character count component without message", () => {
const { body } = document;

afterEach(() => {
body.textContent = '';
body.textContent = "";
CharacterCount.off(body);
});

it('should throw an error when a character count component is created with no message element', () => {
it("should throw an error when a character count component is created with no message element", () => {
body.innerHTML = INVALID_TEMPLATE_NO_MESSAGE;
assert.throws(() => CharacterCount.on(), {
message: '.usa-character-count is missing inner .usa-character-count__message',
message:
".usa-character-count is missing inner .usa-character-count__message",
});
});
});
21 changes: 12 additions & 9 deletions spec/unit/character-count/invalid-template-no-wrapper.spec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const CharacterCount = require('../../../src/js/components/character-count');
const fs = require("fs");
const path = require("path");
const assert = require("assert");
const CharacterCount = require("../../../src/js/components/character-count");

const INVALID_TEMPLATE_NO_WRAPPER = fs.readFileSync(path.join(__dirname, '/invalid-template-no-wrapper.template.html'));
const INVALID_TEMPLATE_NO_WRAPPER = fs.readFileSync(
path.join(__dirname, "/invalid-template-no-wrapper.template.html")
);

describe('character count input without wrapping element', () => {
describe("character count input without wrapping element", () => {
const { body } = document;

afterEach(() => {
body.textContent = '';
body.textContent = "";
CharacterCount.off(body);
});

it('should throw an error when a character count component is created with no wrapping class', () => {
it("should throw an error when a character count component is created with no wrapping class", () => {
body.innerHTML = INVALID_TEMPLATE_NO_WRAPPER;
assert.throws(() => CharacterCount.on(), {
message: '.usa-character-count__field is missing outer .usa-character-count',
message:
".usa-character-count__field is missing outer .usa-character-count",
});
});
});
23 changes: 18 additions & 5 deletions spec/unit/combo-box/combo-box.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe("combo box component", () => {
let select;
let list;
let toggle;
let status;

beforeEach(() => {
body.innerHTML = TEMPLATE;
Expand All @@ -24,6 +25,7 @@ describe("combo box component", () => {
input = root.querySelector(".usa-combo-box__input");
toggle = root.querySelector(".usa-combo-box__toggle-list");
select = root.querySelector(".usa-combo-box__select");
status = root.querySelector(".usa-combo-box__status");
list = root.querySelector(".usa-combo-box__list");
});

Expand Down Expand Up @@ -314,11 +316,18 @@ describe("combo box component", () => {
1,
"should show no results list item"
);
assert.strictEqual(
list.children[0].textContent,
"No results found",
"should show the no results list item"
);
});

it("status should not allow innerHTML", () => {
input.value = "Ap";
EVENTS.input(input);

assert.ok(!list.hidden, "should display the option list");
assert.ok(status.innerHTML, "9 results available.");

Array.from(status.childNodes).forEach((childNode) => {
assert.strictEqual(childNode.nodeType, Node.TEXT_NODE);
});
});

it("should show the list when pressing down from an empty input", () => {
Expand Down Expand Up @@ -512,4 +521,8 @@ describe("combo box component", () => {
});
});
});

it("should have attribute type of string", () => {
assert.strictEqual(typeof(input.getAttribute("aria-label")), 'string')
});
});
2 changes: 1 addition & 1 deletion spec/unit/combo-box/combo-box.template.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<form class="usa-form">
<label class="usa-label" for="fruit">Select a fruit</label>
<div class="usa-combo-box">
<select id="fruit" name="fruit" class="usa-select" required>
<select id="fruit" name="fruit" class="usa-select" required aria-label="&lt;img src='' onerror=alert('ouch')&gt;">
<option value>Select a fruit</option>
<option value="apple">Apple</option>
<option value="apricot">Apricot</option>
Expand Down
30 changes: 15 additions & 15 deletions spec/unit/combo-box/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ const EVENTS = {};
* send a click event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.click = el => {
EVENTS.click = (el) => {
const evt = new MouseEvent("click", {
view: el.ownerDocument.defaultView,
bubbles: true,
cancelable: true
cancelable: true,
});
el.dispatchEvent(evt);
};
Expand All @@ -19,10 +19,10 @@ EVENTS.click = el => {
* send a focusout event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.focusout = el => {
EVENTS.focusout = (el) => {
const evt = new Event("focusout", {
bubbles: true,
cancelable: true
cancelable: true,
});
el.dispatchEvent(evt);
};
Expand All @@ -32,11 +32,11 @@ EVENTS.focusout = el => {
* @param {HTMLElement} el the element to sent the event to
* @returns {{preventDefaultSpy: sinon.SinonSpy<[], void>}}
*/
EVENTS.keydownEnter = el => {
EVENTS.keydownEnter = (el) => {
const evt = new KeyboardEvent("keydown", {
bubbles: true,
key: "Enter",
keyCode: 13
keyCode: 13,
});
const preventDefaultSpy = sinon.spy(evt, "preventDefault");
el.dispatchEvent(evt);
Expand All @@ -47,11 +47,11 @@ EVENTS.keydownEnter = el => {
* send a keydown Escape event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.keydownEscape = el => {
EVENTS.keydownEscape = (el) => {
const evt = new KeyboardEvent("keydown", {
bubbles: true,
key: "Escape",
keyCode: 27
keyCode: 27,
});
el.dispatchEvent(evt);
};
Expand All @@ -60,10 +60,10 @@ EVENTS.keydownEscape = el => {
* send a keydown Tab event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.keydownTab = el => {
EVENTS.keydownTab = (el) => {
const evt = new KeyboardEvent("keydown", {
bubbles: true,
key: "Tab"
key: "Tab",
});
el.dispatchEvent(evt);
};
Expand All @@ -72,10 +72,10 @@ EVENTS.keydownTab = el => {
* send a keydown ArrowDown event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.keydownArrowDown = el => {
EVENTS.keydownArrowDown = (el) => {
const evt = new KeyboardEvent("keydown", {
bubbles: true,
key: "ArrowDown"
key: "ArrowDown",
});
el.dispatchEvent(evt);
};
Expand All @@ -84,10 +84,10 @@ EVENTS.keydownArrowDown = el => {
* send a keydown ArrowUp event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.keydownArrowUp = el => {
EVENTS.keydownArrowUp = (el) => {
const evt = new KeyboardEvent("keydown", {
bubbles: true,
key: "ArrowUp"
key: "ArrowUp",
});
el.dispatchEvent(evt);
};
Expand All @@ -96,7 +96,7 @@ EVENTS.keydownArrowUp = el => {
* send an input event
* @param {HTMLElement} el the element to sent the event to
*/
EVENTS.input = el => {
EVENTS.input = (el) => {
el.dispatchEvent(new KeyboardEvent("input", { bubbles: true }));
};

Expand Down
20 changes: 11 additions & 9 deletions spec/unit/combo-box/invalid-template-no-select.spec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const ComboBox = require('../../../src/js/components/combo-box');
const fs = require("fs");
const path = require("path");
const assert = require("assert");
const ComboBox = require("../../../src/js/components/combo-box");

const INVALID_TEMPLATE_NO_MESSAGE = fs.readFileSync(path.join(__dirname, '/invalid-template-no-select.template.html'));
const INVALID_TEMPLATE_NO_MESSAGE = fs.readFileSync(
path.join(__dirname, "/invalid-template-no-select.template.html")
);

describe('character count component without message', () => {
describe("character count component without message", () => {
const { body } = document;

afterEach(() => {
body.textContent = '';
body.textContent = "";
ComboBox.off(body);
});

it('should throw an error when a combo box component is created with no select element', () => {
it("should throw an error when a combo box component is created with no select element", () => {
body.innerHTML = INVALID_TEMPLATE_NO_MESSAGE;
assert.throws(() => ComboBox.on(), {
message: '.usa-combo-box is missing inner select',
message: ".usa-combo-box is missing inner select",
});
});
});
Loading

0 comments on commit 36b25d6

Please sign in to comment.