Skip to content

Commit

Permalink
Merge pull request #692 from tosmolka/tosmolka/xhtml-lowercase
Browse files Browse the repository at this point in the history
Make TAG and ATTR cfg options case-sensitive when parsing XHTML
  • Loading branch information
cure53 committed Jun 6, 2022
2 parents 87b29de + 3ad7750 commit 79e622c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 25 deletions.
60 changes: 37 additions & 23 deletions src/purify.js
Expand Up @@ -380,29 +380,55 @@ function createDOMPurify(window = getGlobal()) {
/* Shield configuration object from prototype pollution */
cfg = clone(cfg);

PARSER_MEDIA_TYPE =
// eslint-disable-next-line unicorn/prefer-includes
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1
? (PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE)
: (PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE);

// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
transformCaseFunc =
PARSER_MEDIA_TYPE === 'application/xhtml+xml'
? (x) => x
: stringToLowerCase;

/* Set configuration parameters */
ALLOWED_TAGS =
'ALLOWED_TAGS' in cfg
? addToSet({}, cfg.ALLOWED_TAGS)
? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)
: DEFAULT_ALLOWED_TAGS;
ALLOWED_ATTR =
'ALLOWED_ATTR' in cfg
? addToSet({}, cfg.ALLOWED_ATTR)
? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)
: DEFAULT_ALLOWED_ATTR;
URI_SAFE_ATTRIBUTES =
'ADD_URI_SAFE_ATTR' in cfg
? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR)
? addToSet(
clone(DEFAULT_URI_SAFE_ATTRIBUTES),
cfg.ADD_URI_SAFE_ATTR,
transformCaseFunc
)
: DEFAULT_URI_SAFE_ATTRIBUTES;
DATA_URI_TAGS =
'ADD_DATA_URI_TAGS' in cfg
? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS)
? addToSet(
clone(DEFAULT_DATA_URI_TAGS),
cfg.ADD_DATA_URI_TAGS,
transformCaseFunc
)
: DEFAULT_DATA_URI_TAGS;
FORBID_CONTENTS =
'FORBID_CONTENTS' in cfg
? addToSet({}, cfg.FORBID_CONTENTS)
? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)
: DEFAULT_FORBID_CONTENTS;
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
FORBID_TAGS =
'FORBID_TAGS' in cfg
? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)
: {};
FORBID_ATTR =
'FORBID_ATTR' in cfg
? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)
: {};
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
Expand Down Expand Up @@ -443,18 +469,6 @@ function createDOMPurify(window = getGlobal()) {
cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
}

PARSER_MEDIA_TYPE =
// eslint-disable-next-line unicorn/prefer-includes
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1
? (PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE)
: (PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE);

// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
transformCaseFunc =
PARSER_MEDIA_TYPE === 'application/xhtml+xml'
? (x) => x
: stringToLowerCase;

if (SAFE_FOR_TEMPLATES) {
ALLOW_DATA_ATTR = false;
}
Expand Down Expand Up @@ -497,27 +511,27 @@ function createDOMPurify(window = getGlobal()) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}

addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}

if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}

addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}

if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
}

if (cfg.FORBID_CONTENTS) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
FORBID_CONTENTS = clone(FORBID_CONTENTS);
}

addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
}

/* Add #text in case KEEP_CONTENT is set to true */
Expand Down
5 changes: 3 additions & 2 deletions src/utils.js
Expand Up @@ -58,7 +58,8 @@ export function unconstruct(func) {
}

/* Add properties to a lookup table */
export function addToSet(set, array) {
export function addToSet(set, array, transformCaseFunc) {
transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase;
if (setPrototypeOf) {
// Make 'in' and truthy checks like Boolean(set.constructor)
// independent of any properties defined on Object.prototype.
Expand All @@ -70,7 +71,7 @@ export function addToSet(set, array) {
while (l--) {
let element = array[l];
if (typeof element === 'string') {
const lcElement = stringToLowerCase(element);
const lcElement = transformCaseFunc(element);
if (lcElement !== element) {
// Config presets (e.g. tags.js, attrs.js) are immutable.
if (!isFrozen(array)) {
Expand Down
20 changes: 20 additions & 0 deletions test/test-suite.js
Expand Up @@ -1842,6 +1842,26 @@
});
});

QUnit.test(
'Config-Flag tests: PARSER_MEDIA_TYPE + ALLOWED_TAGS/ALLOWED_ATTR',
function (assert) {
assert.contains(
DOMPurify.sanitize(
'<a href="#">abc</a><CustomTag customattr="bar" CustomAttr="foo"/>',
{
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ALLOWED_TAGS: ['a', 'CustomTag'],
ALLOWED_ATTR: ['href', 'CustomAttr'],
}
),
[
'<a xmlns="http://www.w3.org/1999/xhtml" href="#">abc</a>' +
'<CustomTag xmlns="http://www.w3.org/1999/xhtml" CustomAttr="foo"></CustomTag>',
]
);
}
);

QUnit.test('Test invalid xml', function (assert) {
var tests = [
{
Expand Down

0 comments on commit 79e622c

Please sign in to comment.