Skip to content

Commit

Permalink
Merge pull request #729 from kevin-deyoungster/kdeyoungster/xml
Browse files Browse the repository at this point in the history
Add ADD_NAMESPACES option to support strict XML documents
  • Loading branch information
cure53 committed Nov 10, 2022
2 parents 00ad011 + 36fc276 commit 5f77429
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 39 deletions.
30 changes: 22 additions & 8 deletions dist/purify.cjs.js

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

2 changes: 1 addition & 1 deletion dist/purify.cjs.js.map

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions dist/purify.es.js

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

2 changes: 1 addition & 1 deletion dist/purify.es.js.map

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions dist/purify.js

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

2 changes: 1 addition & 1 deletion dist/purify.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/purify.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/purify.min.js.map

Large diffs are not rendered by default.

39 changes: 34 additions & 5 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,6 +366,14 @@ function createDOMPurify(window = getGlobal()) {
let NAMESPACE = HTML_NAMESPACE;
let IS_EMPTY_INPUT = false;

/* 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;
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
Expand Down Expand Up @@ -411,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 @@ -423,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 @@ -634,14 +647,18 @@ 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);

if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
return false;
}

if (element.namespaceURI === SVG_NAMESPACE) {
// The only way to switch from HTML namespace to SVG
// is via <svg>. If it happens via any other tag, then
Expand All @@ -650,7 +667,7 @@ function createDOMPurify(window = getGlobal()) {
return tagName === 'svg';
}

// The only way to switch from MathML to SVG is via
// The only way to switch from MathML to SVG is via`
// svg if parent is either <annotation-xml> or MathML
// text integration points.
if (parent.namespaceURI === MATHML_NAMESPACE) {
Expand Down Expand Up @@ -711,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 @@ -790,7 +816,10 @@ 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
Loading

0 comments on commit 5f77429

Please sign in to comment.