Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Prevent axe-core crashing on “-“ as a class name #884

Merged
merged 1 commit into from
May 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions lib/core/utils/escape-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
axe.utils.escapeSelector = function (value) {
'use strict';
/*eslint no-bitwise: 0, eqeqeq: 0, complexity: ["error",27],
max-statements:["error", 23], one-var: 0, -W041: 0 */
max-statements:["error", 25], one-var: 0, -W041: 0 */
var string = String(value);
var length = string.length;
var index = -1;
Expand All @@ -20,33 +20,33 @@ axe.utils.escapeSelector = function (value) {
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.

// If the character is NULL (U+0000), then throw an
// `InvalidCharacterError` exception and terminate these steps.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
throw new Error('INVALID_CHARACTER_ERR');
result += '\uFFFD';
continue;
}

if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or
// [\7F-\9F] (U+007F to U+009F), […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) ||
(codeUnit >= 0x007F && codeUnit <= 0x009F) ||
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) ||
codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002D)
) {
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}

// If the character is the second character and is `-` (U+002D) and the
// first character is `-` as well, […]
if (index == 1 && codeUnit == 0x002D && firstCodeUnit == 0x002D) {
// http://dev.w3.org/csswg/cssom/#escape-a-character
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
if (index == 0 && length == 1 && codeUnit == 0x002D) {
result += '\\' + string.charAt(index);
continue;
}
Expand All @@ -69,7 +69,7 @@ axe.utils.escapeSelector = function (value) {
}

// Otherwise, the escaped character.
// http://dev.w3.org/csswg/cssom/#escape-a-character
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);

}
Expand Down
57 changes: 34 additions & 23 deletions test/core/utils/escape-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,37 @@ describe('utils.escapeSelector', function () {
'use strict';
var escapeSelector = axe.utils.escapeSelector;

it('should serialize strings based on CSSOM spec', function () {
it('leaves characters that do not need to escape alone', function () {
assert.equal(escapeSelector('a0b'), 'a0b');
assert.equal(escapeSelector('a1b'), 'a1b');
assert.equal(escapeSelector('a2b'), 'a2b');
assert.equal(escapeSelector('a3b'), 'a3b');
assert.equal(escapeSelector('a4b'), 'a4b');
assert.equal(escapeSelector('a5b'), 'a5b');
assert.equal(escapeSelector('a6b'), 'a6b');
assert.equal(escapeSelector('a7b'), 'a7b');
assert.equal(escapeSelector('a8b'), 'a8b');
assert.equal(escapeSelector('a9b'), 'a9b');
assert.equal(escapeSelector('a0123456789b'), 'a0123456789b');
assert.equal(escapeSelector('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz');
assert.equal(escapeSelector('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
});

assert.throws(function () { escapeSelector('\0'); }, Error);
assert.throws(function () { escapeSelector('a\0'); }, Error);
assert.throws(function () { escapeSelector('a\0b'); }, Error);
it('escapes null characters', function () {
assert.equal(escapeSelector('\0'), '\uFFFD');
assert.equal(escapeSelector('a\0'), 'a\uFFFD');
assert.equal(escapeSelector('a\0b'), 'a\uFFFDb');
});

it('stringifies non-string characters', function () {
assert.equal(escapeSelector(), 'undefined');
assert.equal(escapeSelector(true), 'true');
assert.equal(escapeSelector(false), 'false');
assert.equal(escapeSelector(null), 'null');
assert.equal(escapeSelector(''), '');
});

assert.equal(escapeSelector('\x01\x02\x1E\x1F'), '\\1 \\2 \\1e \\1f ');

it('escapes strings starting with a number', function () {
assert.equal(escapeSelector('0a'), '\\30 a');
assert.equal(escapeSelector('1a'), '\\31 a');
assert.equal(escapeSelector('2a'), '\\32 a');
Expand All @@ -27,18 +44,15 @@ describe('utils.escapeSelector', function () {
assert.equal(escapeSelector('7a'), '\\37 a');
assert.equal(escapeSelector('8a'), '\\38 a');
assert.equal(escapeSelector('9a'), '\\39 a');
});

assert.equal(escapeSelector('a0b'), 'a0b');
assert.equal(escapeSelector('a1b'), 'a1b');
assert.equal(escapeSelector('a2b'), 'a2b');
assert.equal(escapeSelector('a3b'), 'a3b');
assert.equal(escapeSelector('a4b'), 'a4b');
assert.equal(escapeSelector('a5b'), 'a5b');
assert.equal(escapeSelector('a6b'), 'a6b');
assert.equal(escapeSelector('a7b'), 'a7b');
assert.equal(escapeSelector('a8b'), 'a8b');
assert.equal(escapeSelector('a9b'), 'a9b');
it('only escapes "-" when before a number, or on its own', function () {
assert.equal(escapeSelector('-123'), '-\\31 23');
assert.equal(escapeSelector('-'), '\\-');
assert.equal(escapeSelector('--a'), '--a');
});

it('escapes characters staring with a negative number', function () {
assert.equal(escapeSelector('-0a'), '-\\30 a');
assert.equal(escapeSelector('-1a'), '-\\31 a');
assert.equal(escapeSelector('-2a'), '-\\32 a');
Expand All @@ -49,23 +63,20 @@ describe('utils.escapeSelector', function () {
assert.equal(escapeSelector('-7a'), '-\\37 a');
assert.equal(escapeSelector('-8a'), '-\\38 a');
assert.equal(escapeSelector('-9a'), '-\\39 a');
});

assert.equal(escapeSelector('--a'), '-\\-a');

assert.equal(escapeSelector('\x80\x2D\x5F\xA9'), '\\80 \x2D\x5F\xA9');
it('escapes hex character codes', function () {
assert.equal(escapeSelector('\x80\x2D\x5F\xA9'), '\x80\x2D\x5F\xA9');
assert.equal(escapeSelector('\xA0\xA1\xA2'), '\xA0\xA1\xA2');
assert.equal(escapeSelector('a0123456789b'), 'a0123456789b');
assert.equal(escapeSelector('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz');
assert.equal(escapeSelector('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');

assert.equal(escapeSelector('\x01\x02\x1E\x1F'), '\\1 \\2 \\1e \\1f ');
assert.equal(escapeSelector('\x20\x21\x78\x79'), '\\ \\!xy');

// astral symbol (U+1D306 TETRAGRAM FOR CENTRE)
assert.equal(escapeSelector('\uD834\uDF06'), '\uD834\uDF06');
// lone surrogates
assert.equal(escapeSelector('\uDF06'), '\uDF06');
assert.equal(escapeSelector('\uD834'), '\uD834');

});

});