Skip to content

Commit

Permalink
Experiment with ALLOWED_NAMESPACES
Browse files Browse the repository at this point in the history
  • Loading branch information
tosmolka authored and kevin-deyoungster committed Nov 8, 2022
1 parent 5a425dc commit c2c1b11
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 37 deletions.
44 changes: 27 additions & 17 deletions src/purify.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
stringMatch,
stringReplace,
stringToLowerCase,
stringToString,
stringIndexOf,
stringTrim,
regExpTest,
Expand Down Expand Up @@ -365,8 +366,13 @@ function createDOMPurify(window = getGlobal()) {
let NAMESPACE = HTML_NAMESPACE;
let IS_EMPTY_INPUT = false;

/* Additional namespaces to allow, for in XHTML/XML case */
let ADD_NAMESPACES = null;
/* Allowed XHTML+XML namespaces */
let ALLOWED_NAMESPACES = null;
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
MATHML_NAMESPACE,
SVG_NAMESPACE,
HTML_NAMESPACE,
], stringToString);

/* Parsing of strict XHTML documents */
let PARSER_MEDIA_TYPE;
Expand Down Expand Up @@ -414,7 +420,7 @@ function createDOMPurify(window = getGlobal()) {
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
transformCaseFunc =
PARSER_MEDIA_TYPE === 'application/xhtml+xml'
? (x) => x
? stringToString
: stringToLowerCase;

/* Set configuration parameters */
Expand All @@ -426,6 +432,10 @@ function createDOMPurify(window = getGlobal()) {
'ALLOWED_ATTR' in cfg
? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)
: DEFAULT_ALLOWED_ATTR;
ALLOWED_NAMESPACES =
'ALLOWED_NAMESPACES' in cfg
? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString)
: DEFAULT_ALLOWED_NAMESPACES;
URI_SAFE_ATTRIBUTES =
'ADD_URI_SAFE_ATTR' in cfg
? addToSet(
Expand Down Expand Up @@ -548,10 +558,6 @@ function createDOMPurify(window = getGlobal()) {
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}

if (cfg.ADD_NAMESPACES) {
ADD_NAMESPACES = addToSet({}, cfg.ADD_NAMESPACES, transformCaseFunc);
}

if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
}
Expand Down Expand Up @@ -641,21 +647,16 @@ function createDOMPurify(window = getGlobal()) {
// can be null. We just simulate parent in this case.
if (!parent || !parent.tagName) {
parent = {
namespaceURI: HTML_NAMESPACE,
namespaceURI: NAMESPACE,
tagName: 'template',
};
}

const tagName = stringToLowerCase(element.tagName);
const parentTagName = stringToLowerCase(parent.tagName);

/* For XHTML and XML documents that support custom namespaces */
if (
PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&
ADD_NAMESPACES &&
element.namespaceURI in ADD_NAMESPACES
) {
return true;
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
return false;
}

if (element.namespaceURI === SVG_NAMESPACE) {
Expand Down Expand Up @@ -727,9 +728,18 @@ function createDOMPurify(window = getGlobal()) {
);
}

// For XHTML and XML documents that support custom namespaces
if (
PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&
ALLOWED_NAMESPACES[element.namespaceURI]
) {
return true;
}

// The code should never reach this place (this means
// that the element somehow got namespace that is not
// HTML, SVG or MathML). Return false just in case.
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
// Return false just in case.
return false;
};

Expand Down Expand Up @@ -806,7 +816,7 @@ function createDOMPurify(window = getGlobal()) {
leadingWhitespace = matches && matches[0];
}

if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
dirty =
'<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' +
Expand Down
2 changes: 2 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const arrayPush = unapply(Array.prototype.push);
const arraySlice = unapply(Array.prototype.slice);

const stringToLowerCase = unapply(String.prototype.toLowerCase);
const stringToString = unapply(String.prototype.toString);
const stringMatch = unapply(String.prototype.match);
const stringReplace = unapply(String.prototype.replace);
const stringIndexOf = unapply(String.prototype.indexOf);
Expand Down Expand Up @@ -152,6 +153,7 @@ export {
stringMatch,
stringReplace,
stringToLowerCase,
stringToString,
stringTrim,
// Errors
typeErrorCreate,
Expand Down
40 changes: 20 additions & 20 deletions test/test-suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -1803,16 +1803,16 @@
assert.contains(clean, test.expected);
});
});
QUnit.test('Config-Flag tests: ADD_NAMESPACES', function (assert) {
QUnit.test('Config-Flag tests: ALLOWED_NAMESPACES', function (assert) {
const tests = [
// Test when ADD_NAMESPACES is not set, result is empty for XML with custom namespace
// Test when ALLOWED_NAMESPACES is not set, result is empty for XML with custom namespace
{
test:
'<library xmlns="http://www.ibm.com/library"><name>Library 1</name></library>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['library', 'name'],
ALLOWED_TAGS: ['#text', 'library', 'name'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected: '',
},
Expand All @@ -1821,10 +1821,10 @@
test:
'<library xmlns="http://www.ibm.com/library"><name>Library 1</name><dirty onload="alert()" /></library>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['library', 'name'],
ADD_NAMESPACES: ['http://www.ibm.com/library'],
ALLOWED_NAMESPACES: ['http://www.ibm.com/library'],
ALLOWED_TAGS: ['#text', 'library', 'name'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected:
'<library xmlns="http://www.ibm.com/library"><name>Library 1</name></library>',
Expand All @@ -1834,23 +1834,23 @@
test:
'<city><library xmlns="http://www.ibm.com/library"><name>Library 1</name><dirty onload="alert()" /></library></city>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['city', 'library', 'name'],
ADD_NAMESPACES: ['http://www.ibm.com/library'],
ALLOWED_NAMESPACES: ['http://www.w3.org/1999/xhtml', 'http://www.ibm.com/library'],
ALLOWED_TAGS: ['#text', 'city', 'library', 'name'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected:
'<city xmlns="http://www.w3.org/1999/xhtml"><library xmlns="http://www.ibm.com/library"><name>Library 1</name></library></city>',
},
// Test removal of namespaces not listed in ADD_NAMESPACES when input has multiple namespaces
// Test removal of namespaces not listed in ALLOWED_NAMESPACES when input has multiple namespaces
{
test:
'<library xmlns="http://www.ibm.com/library" xmlns:bk="urn:loc.gov:books"><bk:name>Library 1</bk:name><dirty onload="alert()" /></library>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['library', 'bk:name'],
ADD_NAMESPACES: ['http://www.ibm.com/library'],
ALLOWED_NAMESPACES: ['http://www.ibm.com/library'],
ALLOWED_TAGS: ['library', 'bk:name'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected: '<library xmlns="http://www.ibm.com/library"/>',
},
Expand All @@ -1859,14 +1859,14 @@
test:
'<library xmlns="http://www.ibm.com/library" xmlns:bk="urn:loc.gov:books" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><bk:name>Library 1<m:properties>Other Properties</m:properties></bk:name><dirty onload="alert()" /></library>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['library', 'bk:name', 'm:properties'],
ADD_NAMESPACES: [
ALLOWED_NAMESPACES: [
'http://www.ibm.com/library',
'urn:loc.gov:books',
'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
],
ALLOWED_TAGS: ['#text', 'library', 'bk:name', 'm:properties'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected:
'<library xmlns="http://www.ibm.com/library"><bk:name xmlns:bk="urn:loc.gov:books">Library 1<m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">Other Properties</m:properties></bk:name></library>',
Expand All @@ -1876,15 +1876,15 @@
test:
'<library xmlns="http://www.ibm.com/library" xmlns:bk="urn:loc.gov:books" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><bk:name>Library 1<m:properties>Other Properties</m:properties></bk:name><dirty onload="alert()" /></library>',
config: {
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
ADD_TAGS: ['library', 'bk:name'],
FORBID_TAGS: ['m:properties'],
ADD_NAMESPACES: [
ALLOWED_NAMESPACES: [
'http://www.ibm.com/library',
'urn:loc.gov:books',
'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
],
FORBID_TAGS: ['m:properties'],
KEEP_CONTENT: false,
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
},
expected:
'<library xmlns="http://www.ibm.com/library"><bk:name xmlns:bk="urn:loc.gov:books">Library 1</bk:name></library>',
Expand Down

0 comments on commit c2c1b11

Please sign in to comment.