safevalues
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -32,5 +32,6 @@ /** | ||
/** | ||
* Allows the set of data attributes passed. | ||
* Allows all or a definite set of data attributes passed. | ||
* | ||
* These values must be prefixed with "data-" | ||
* When called without arguments, all data attributes are allowed. | ||
* When a set of attributes is passed, its values must be prefixed with "data-" | ||
* | ||
@@ -40,3 +41,3 @@ * If called with onlyAllowElements or onlyAllowAttributes, those methods must | ||
*/ | ||
allowDataAttributes(attributes: string[]): this; | ||
allowDataAttributes(attributes?: string[]): this; | ||
/** | ||
@@ -124,5 +125,14 @@ * Preserves style attributes. Note that the sanitizer won't parse and | ||
private transitionsAllowed; | ||
private openShadow; | ||
allowAnimations(): this; | ||
allowTransitions(): this; | ||
/** | ||
* Sets the shadow DOM mode to 'open'. | ||
* | ||
* While this method is not formally restricted, it can potentially be used to | ||
* bypass the security guarantees of the CSS sanitizer. If you need open | ||
* shadow DOM, please contact ise-web-members@ to discuss your use case. | ||
*/ | ||
withOpenShadow(): this; | ||
/** | ||
* Builds a CSS sanitizer. | ||
@@ -129,0 +139,0 @@ * |
@@ -42,3 +42,3 @@ "use strict"; | ||
} | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -70,3 +70,3 @@ } | ||
} | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -100,9 +100,10 @@ } | ||
} | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, elementPolicies, allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, elementPolicies, allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
} | ||
/** | ||
* Allows the set of data attributes passed. | ||
* Allows all or a definite set of data attributes passed. | ||
* | ||
* These values must be prefixed with "data-" | ||
* When called without arguments, all data attributes are allowed. | ||
* When a set of attributes is passed, its values must be prefixed with "data-" | ||
* | ||
@@ -113,2 +114,8 @@ * If called with onlyAllowElements or onlyAllowAttributes, those methods must | ||
allowDataAttributes(attributes) { | ||
if (attributes === undefined) { | ||
const globallyAllowedAttributePrefixes = new Set(this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
globallyAllowedAttributePrefixes.add('data-'); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, globallyAllowedAttributePrefixes); | ||
return this; | ||
} | ||
const allowedGlobalAttributes = new Set(this.sanitizerTable.allowedGlobalAttributes); | ||
@@ -121,3 +128,3 @@ for (const attribute of attributes) { | ||
} | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -137,3 +144,3 @@ } | ||
}); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -149,3 +156,3 @@ } | ||
allowedGlobalAttributes.add('class'); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -160,3 +167,3 @@ } | ||
allowedGlobalAttributes.add('id'); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -180,3 +187,3 @@ } | ||
.add('list'); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -253,2 +260,3 @@ } | ||
this.transitionsAllowed = false; | ||
this.openShadow = false; | ||
} | ||
@@ -264,2 +272,13 @@ allowAnimations() { | ||
/** | ||
* Sets the shadow DOM mode to 'open'. | ||
* | ||
* While this method is not formally restricted, it can potentially be used to | ||
* bypass the security guarantees of the CSS sanitizer. If you need open | ||
* shadow DOM, please contact ise-web-members@ to discuss your use case. | ||
*/ | ||
withOpenShadow() { | ||
this.openShadow = true; | ||
return this; | ||
} | ||
/** | ||
* Builds a CSS sanitizer. | ||
@@ -281,3 +300,3 @@ * | ||
const styleAttributeSanitizer = (cssText) => (0, sanitizer_js_1.sanitizeStyleAttribute)(cssText, allowlists_js_1.CSS_PROPERTY_ALLOWLIST, allowlists_js_1.CSS_FUNCTION_ALLOWLIST, this.resourceUrlPolicy, propertyDiscarders); | ||
return new html_sanitizer_js_1.HtmlSanitizerImpl(this.sanitizerTable, secrets_js_1.secretToken, styleElementSanitizer, styleAttributeSanitizer, this.resourceUrlPolicy); | ||
return new html_sanitizer_js_1.HtmlSanitizerImpl(this.sanitizerTable, secrets_js_1.secretToken, styleElementSanitizer, styleAttributeSanitizer, this.resourceUrlPolicy, this.openShadow); | ||
} | ||
@@ -295,5 +314,5 @@ extendSanitizerTableForCss() { | ||
allowedGlobalAttributes.add('class'); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new sanitizer_table_js_1.SanitizerTable(allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
} | ||
} | ||
exports.CssSanitizerBuilder = CssSanitizerBuilder; |
@@ -49,4 +49,5 @@ /** | ||
private readonly resourceUrlPolicy?; | ||
private readonly openShadow?; | ||
private changes; | ||
constructor(sanitizerTable: SanitizerTable, token: object, styleElementSanitizer?: CssSanitizationFn | undefined, styleAttributeSanitizer?: CssSanitizationFn | undefined, resourceUrlPolicy?: ResourceUrlPolicy | undefined); | ||
constructor(sanitizerTable: SanitizerTable, token: object, styleElementSanitizer?: CssSanitizationFn | undefined, styleAttributeSanitizer?: CssSanitizationFn | undefined, resourceUrlPolicy?: ResourceUrlPolicy | undefined, openShadow?: boolean | undefined); | ||
sanitizeAssertUnchanged(html: string): SafeHtml; | ||
@@ -53,0 +54,0 @@ sanitize(html: string): SafeHtml; |
@@ -22,3 +22,3 @@ "use strict"; | ||
class HtmlSanitizerImpl { | ||
constructor(sanitizerTable, token, styleElementSanitizer, styleAttributeSanitizer, resourceUrlPolicy) { | ||
constructor(sanitizerTable, token, styleElementSanitizer, styleAttributeSanitizer, resourceUrlPolicy, openShadow) { | ||
this.sanitizerTable = sanitizerTable; | ||
@@ -28,2 +28,3 @@ this.styleElementSanitizer = styleElementSanitizer; | ||
this.resourceUrlPolicy = resourceUrlPolicy; | ||
this.openShadow = openShadow; | ||
this.changes = []; | ||
@@ -57,3 +58,4 @@ (0, secrets_js_1.ensureTokenIsValid)(token); | ||
const elem = document.createElement('safevalues-with-css'); | ||
const shadow = elem.attachShadow({ mode: 'closed' }); | ||
const mode = this.openShadow ? 'open' : 'closed'; | ||
const shadow = elem.attachShadow({ mode }); | ||
const sanitized = this.sanitizeToFragmentInternal(htmlWithCss, inertDocument); | ||
@@ -60,0 +62,0 @@ const internalStyle = document.createElement('style'); |
@@ -271,2 +271,3 @@ "use strict"; | ||
'checked', | ||
'cite', | ||
'color', | ||
@@ -276,2 +277,3 @@ 'cols', | ||
'controls', | ||
'controlslist', | ||
'datetime', | ||
@@ -302,2 +304,3 @@ 'disabled', | ||
'placeholder', | ||
'poster', | ||
'preload', | ||
@@ -356,8 +359,2 @@ 'rel', | ||
[ | ||
'cite', | ||
{ | ||
policyAction: sanitizer_table_js_1.AttributePolicyAction.KEEP_AND_SANITIZE_URL, | ||
}, | ||
], | ||
[ | ||
'loading', | ||
@@ -374,8 +371,2 @@ { | ||
[ | ||
'poster', | ||
{ | ||
policyAction: sanitizer_table_js_1.AttributePolicyAction.KEEP_AND_SANITIZE_URL, | ||
}, | ||
], | ||
[ | ||
'target', | ||
@@ -396,2 +387,2 @@ { | ||
*/ | ||
exports.DEFAULT_SANITIZER_TABLE = new sanitizer_table_js_1.SanitizerTable(new Set(ALLOWED_ELEMENTS), new Map(ELEMENT_POLICIES), new Set(ALLOWED_GLOBAL_ATTRIBUTES), new Map(GLOBAL_ATTRIBUTE_POLICIES)); | ||
exports.DEFAULT_SANITIZER_TABLE = new sanitizer_table_js_1.SanitizerTable(new Set(ALLOWED_ELEMENTS), new Map(ELEMENT_POLICIES), new Set(ALLOWED_GLOBAL_ATTRIBUTES), new Map(GLOBAL_ATTRIBUTE_POLICIES), undefined); |
@@ -12,4 +12,4 @@ /** | ||
readonly globalAttributePolicies: ReadonlyMap<string, AttributePolicy>; | ||
readonly globallyAllowedAttributePrefixes?: ReadonlySet<string> | undefined; | ||
constructor(allowedElements: ReadonlySet<string>, elementPolicies: ReadonlyMap<string, ElementPolicy>, allowedGlobalAttributes: ReadonlySet<string>, globalAttributePolicies: ReadonlyMap<string, AttributePolicy>, globallyAllowedAttributePrefixes?: ReadonlySet<string> | undefined); | ||
readonly globallyAllowedAttributePrefixes: ReadonlySet<string> | undefined; | ||
constructor(allowedElements: ReadonlySet<string>, elementPolicies: ReadonlyMap<string, ElementPolicy>, allowedGlobalAttributes: ReadonlySet<string>, globalAttributePolicies: ReadonlyMap<string, AttributePolicy>, globallyAllowedAttributePrefixes: ReadonlySet<string> | undefined); | ||
isAllowedElement(elementName: string): boolean; | ||
@@ -16,0 +16,0 @@ getAttributePolicy(attributeName: string, elementName: string): AttributePolicy; |
@@ -10,2 +10,2 @@ /** | ||
*/ | ||
export declare const SECURITY_SENSITIVE_ATTRIBUTES: readonly ["src", "srcdoc", "codebase", "data", "href", "rel", "action", "formaction", "sandbox", "cite", "poster", "icon"]; | ||
export declare const SECURITY_SENSITIVE_ATTRIBUTES: readonly ["src", "srcdoc", "codebase", "data", "href", "rel", "action", "formaction", "sandbox", "icon"]; |
@@ -24,5 +24,3 @@ "use strict"; | ||
'sandbox', | ||
'cite', | ||
'poster', | ||
'icon', | ||
]; |
@@ -14,2 +14,3 @@ /** | ||
import { SafeHtml } from '../../internals/html_impl.js'; | ||
import { TrustedResourceUrl } from '../../internals/resource_url_impl.js'; | ||
declare type ScriptOrStyle = HTMLScriptElement | HTMLStyleElement | SVGScriptElement | SVGStyleElement; | ||
@@ -42,3 +43,3 @@ /** | ||
/** | ||
* The safe alternative to Element#setAttribute. The function takes a list of | ||
* A safe alternative to Element#setAttribute. The function takes a list of | ||
* `SafeAttributePrefix`, making developer intention explicit. The attribute | ||
@@ -49,2 +50,45 @@ * to be set must has one of the safe prefixes, otherwise the function throws | ||
export declare function setElementPrefixedAttribute(attrPrefixes: readonly SafeAttributePrefix[], e: Element, attr: string, value: string): void; | ||
/** | ||
* A safe alternative to Element#setAttribute. | ||
* | ||
* The function has essentially the same signature as `Element.setAttribute`, | ||
* but requires a safe type (or sanitizes the value) when used with a security | ||
* sensitive attribute. It does this by forwarding the call to the | ||
* element-specific setters within `safevalues/dom`. | ||
* | ||
* Note that this function doesn't currently support elements outside of the | ||
* html namespace & might throw if used with the wrong type of element or | ||
* attribute value | ||
* | ||
* If code size is a concern, consider using `setPrefixedAttribute`, or the | ||
* element-specific setters. | ||
* | ||
* The security sensitive element/attributes pairs are the following: | ||
* - anchor#href -> forwarded to `setAnchorHref` | ||
* - area#href -> forwarded to `setAreaHref` | ||
* - base#href -> forwarded to `setBaseHref` | ||
* - button#formaction -> forwarded to `setButtonFormaction` | ||
* - embed#src -> forwarded to `setEmbedSrc` | ||
* - form#action -> forwarded to `setFormAction` | ||
* - iframe#src -> forwarded to `setIframeSrc` | ||
* - iframe#srcdoc -> forwarded to `setIframeSrcdoc` | ||
* - iframe#sandbox -> rejected, use `setIframeSrcWithIntent` or | ||
* `setIframeSrcdocWithIntent` instead | ||
* - input#formaction -> forwarded to `setInputFormaction` | ||
* - link#href -> rejected, use `setLinkHrefAndRel` instead | ||
* - link#rel -> rejected, use `setLinkHrefAndRel` instead | ||
* - object#data -> forwarded to `setObjectData` | ||
* - script#src -> forwarded to `setScriptSrc` | ||
* - global attributes: | ||
* - target -> forwarded to `el.setAttribute` | ||
* - cite -> forwarded to `el.setAttribute` | ||
* - poster -> forwarded to `el.setAttribute` | ||
* - srcset -> forwarded to `el.setAttribute` | ||
* - src -> forwarded to `el.setAttribute` | ||
* - href -> forwarded to `el.setAttribute` | ||
* - any attribute starting with `on` -> rejected | ||
* | ||
* Every other attribute is set as is using `element.setAttribute` | ||
*/ | ||
export declare function setElementAttribute(el: HTMLElement, attr: string, value: string | TrustedResourceUrl | SafeHtml): void; | ||
export {}; |
@@ -8,3 +8,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.setElementPrefixedAttribute = exports.buildPrefixedAttributeSetter = exports.elementInsertAdjacentHtml = exports.setElementOuterHtml = exports.setElementInnerHtml = void 0; | ||
exports.setElementAttribute = exports.setElementPrefixedAttribute = exports.buildPrefixedAttributeSetter = exports.elementInsertAdjacentHtml = exports.setElementOuterHtml = exports.setElementInnerHtml = void 0; | ||
/** | ||
@@ -18,2 +18,12 @@ * @fileoverview This contains safe wrappers for properties that aren't specific | ||
const html_impl_js_1 = require("../../internals/html_impl.js"); | ||
const anchor_js_1 = require("./anchor.js"); | ||
const area_js_1 = require("./area.js"); | ||
const base_js_1 = require("./base.js"); | ||
const button_js_1 = require("./button.js"); | ||
const embed_js_1 = require("./embed.js"); | ||
const form_js_1 = require("./form.js"); | ||
const iframe_js_1 = require("./iframe.js"); | ||
const input_js_1 = require("./input.js"); | ||
const object_js_1 = require("./object.js"); | ||
const script_js_1 = require("./script.js"); | ||
/** | ||
@@ -73,3 +83,3 @@ * Safely set {@link Element.innerHTML} on a given ShadowRoot or Element which | ||
/** | ||
* The safe alternative to Element#setAttribute. The function takes a list of | ||
* A safe alternative to Element#setAttribute. The function takes a list of | ||
* `SafeAttributePrefix`, making developer intention explicit. The attribute | ||
@@ -113,1 +123,102 @@ * to be set must has one of the safe prefixes, otherwise the function throws | ||
} | ||
/** | ||
* A safe alternative to Element#setAttribute. | ||
* | ||
* The function has essentially the same signature as `Element.setAttribute`, | ||
* but requires a safe type (or sanitizes the value) when used with a security | ||
* sensitive attribute. It does this by forwarding the call to the | ||
* element-specific setters within `safevalues/dom`. | ||
* | ||
* Note that this function doesn't currently support elements outside of the | ||
* html namespace & might throw if used with the wrong type of element or | ||
* attribute value | ||
* | ||
* If code size is a concern, consider using `setPrefixedAttribute`, or the | ||
* element-specific setters. | ||
* | ||
* The security sensitive element/attributes pairs are the following: | ||
* - anchor#href -> forwarded to `setAnchorHref` | ||
* - area#href -> forwarded to `setAreaHref` | ||
* - base#href -> forwarded to `setBaseHref` | ||
* - button#formaction -> forwarded to `setButtonFormaction` | ||
* - embed#src -> forwarded to `setEmbedSrc` | ||
* - form#action -> forwarded to `setFormAction` | ||
* - iframe#src -> forwarded to `setIframeSrc` | ||
* - iframe#srcdoc -> forwarded to `setIframeSrcdoc` | ||
* - iframe#sandbox -> rejected, use `setIframeSrcWithIntent` or | ||
* `setIframeSrcdocWithIntent` instead | ||
* - input#formaction -> forwarded to `setInputFormaction` | ||
* - link#href -> rejected, use `setLinkHrefAndRel` instead | ||
* - link#rel -> rejected, use `setLinkHrefAndRel` instead | ||
* - object#data -> forwarded to `setObjectData` | ||
* - script#src -> forwarded to `setScriptSrc` | ||
* - global attributes: | ||
* - target -> forwarded to `el.setAttribute` | ||
* - cite -> forwarded to `el.setAttribute` | ||
* - poster -> forwarded to `el.setAttribute` | ||
* - srcset -> forwarded to `el.setAttribute` | ||
* - src -> forwarded to `el.setAttribute` | ||
* - href -> forwarded to `el.setAttribute` | ||
* - any attribute starting with `on` -> rejected | ||
* | ||
* Every other attribute is set as is using `element.setAttribute` | ||
*/ | ||
function setElementAttribute(el, attr, value) { | ||
if (el.namespaceURI !== 'http://www.w3.org/1999/xhtml') { | ||
throw new Error(`Cannot set attribute '${attr}' on '${el.tagName}'.` + | ||
`Element is not in the HTML namespace`); | ||
} | ||
attr = attr.toLowerCase(); | ||
const key = `${el.tagName} ${attr}`; | ||
switch (key) { | ||
case 'A href': | ||
(0, anchor_js_1.setAnchorHref)(el, value); | ||
return; | ||
case 'AREA href': | ||
(0, area_js_1.setAreaHref)(el, value); | ||
return; | ||
case 'BASE href': | ||
(0, base_js_1.setBaseHref)(el, value); | ||
return; | ||
case 'BUTTON formaction': | ||
(0, button_js_1.setButtonFormaction)(el, value); | ||
return; | ||
case 'EMBED src': | ||
(0, embed_js_1.setEmbedSrc)(el, value); | ||
return; | ||
case 'FORM action': | ||
(0, form_js_1.setFormAction)(el, value); | ||
return; | ||
case 'IFRAME src': | ||
(0, iframe_js_1.setIframeSrc)(el, value); | ||
return; | ||
case 'IFRAME srcdoc': | ||
(0, iframe_js_1.setIframeSrcdoc)(el, value); | ||
return; | ||
case 'IFRAME sandbox': | ||
throw new Error("Can't set 'sandbox' on iframe tags. " + | ||
'Use setIframeSrcWithIntent or setIframeSrcdocWithIntent instead'); | ||
case 'INPUT formaction': | ||
(0, input_js_1.setInputFormaction)(el, value); | ||
return; | ||
case 'LINK href': | ||
throw new Error("Can't set 'href' attribute on link tags. " + | ||
'Use setLinkHrefAndRel instead'); | ||
case 'LINK rel': | ||
throw new Error("Can't set 'rel' attribute on link tags. " + | ||
'Use setLinkHrefAndRel instead'); | ||
case 'OBJECT data': | ||
(0, object_js_1.setObjectData)(el, value); | ||
return; | ||
case 'SCRIPT src': | ||
(0, script_js_1.setScriptSrc)(el, value); | ||
return; | ||
default: | ||
if (/^on./.test(attr)) { | ||
throw new Error(`Attribute "${attr}" looks like an event handler attribute. ` + | ||
`Please use a safe alternative like addEventListener instead.`); | ||
} | ||
el.setAttribute(attr, value); | ||
} | ||
} | ||
exports.setElementAttribute = setElementAttribute; |
@@ -14,3 +14,3 @@ /** | ||
export { setButtonFormaction } from './elements/button.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementAttribute, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { setEmbedSrc } from './elements/embed.js'; | ||
@@ -17,0 +17,0 @@ export { setFormAction } from './elements/form.js'; |
@@ -8,3 +8,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.workerGlobalScopeImportScripts = exports.createWorker = exports.createSharedWorker = exports.windowOpen = exports.getStyleNonce = exports.getScriptNonce = exports.objectUrlFromSafeSource = exports.serviceWorkerContainerRegister = exports.rangeCreateContextualFragment = exports.setLocationHref = exports.locationReplace = exports.locationAssign = exports.globalEval = exports.fetchResourceUrl = exports.domParserParseXml = exports.domParserParseHtml = exports.domParserParseFromString = exports.documentWrite = exports.documentExecCommand = exports.setSvgUseHref = exports.setSvgAttribute = exports.setStyleTextContent = exports.setScriptTextContent = exports.setScriptSrc = exports.setObjectData = exports.setLinkWithResourceUrlHrefAndRel = exports.setLinkHrefAndRel = exports.setInputFormaction = exports.setIframeSrcdoc = exports.setIframeSrc = exports.setFormAction = exports.setEmbedSrc = exports.setElementPrefixedAttribute = exports.setElementOuterHtml = exports.setElementInnerHtml = exports.elementInsertAdjacentHtml = exports.buildPrefixedAttributeSetter = exports.setButtonFormaction = exports.setBaseHref = exports.setAreaHref = exports.setAnchorHref = void 0; | ||
exports.workerGlobalScopeImportScripts = exports.createWorker = exports.createSharedWorker = exports.windowOpen = exports.getStyleNonce = exports.getScriptNonce = exports.objectUrlFromSafeSource = exports.serviceWorkerContainerRegister = exports.rangeCreateContextualFragment = exports.setLocationHref = exports.locationReplace = exports.locationAssign = exports.globalEval = exports.fetchResourceUrl = exports.domParserParseXml = exports.domParserParseHtml = exports.domParserParseFromString = exports.documentWrite = exports.documentExecCommand = exports.setSvgUseHref = exports.setSvgAttribute = exports.setStyleTextContent = exports.setScriptTextContent = exports.setScriptSrc = exports.setObjectData = exports.setLinkWithResourceUrlHrefAndRel = exports.setLinkHrefAndRel = exports.setInputFormaction = exports.setIframeSrcdoc = exports.setIframeSrc = exports.setFormAction = exports.setEmbedSrc = exports.setElementPrefixedAttribute = exports.setElementOuterHtml = exports.setElementInnerHtml = exports.setElementAttribute = exports.elementInsertAdjacentHtml = exports.buildPrefixedAttributeSetter = exports.setButtonFormaction = exports.setBaseHref = exports.setAreaHref = exports.setAnchorHref = void 0; | ||
/** | ||
@@ -25,2 +25,3 @@ * @fileoverview This file re-exports all of the wrappers to ensure that we have | ||
Object.defineProperty(exports, "elementInsertAdjacentHtml", { enumerable: true, get: function () { return element_js_1.elementInsertAdjacentHtml; } }); | ||
Object.defineProperty(exports, "setElementAttribute", { enumerable: true, get: function () { return element_js_1.setElementAttribute; } }); | ||
Object.defineProperty(exports, "setElementInnerHtml", { enumerable: true, get: function () { return element_js_1.setElementInnerHtml; } }); | ||
@@ -27,0 +28,0 @@ Object.defineProperty(exports, "setElementOuterHtml", { enumerable: true, get: function () { return element_js_1.setElementOuterHtml; } }); |
{ | ||
"type": "commonjs", | ||
"version": "1.0.1" | ||
"version": "1.1.0" | ||
} |
@@ -32,5 +32,6 @@ /** | ||
/** | ||
* Allows the set of data attributes passed. | ||
* Allows all or a definite set of data attributes passed. | ||
* | ||
* These values must be prefixed with "data-" | ||
* When called without arguments, all data attributes are allowed. | ||
* When a set of attributes is passed, its values must be prefixed with "data-" | ||
* | ||
@@ -40,3 +41,3 @@ * If called with onlyAllowElements or onlyAllowAttributes, those methods must | ||
*/ | ||
allowDataAttributes(attributes: string[]): this; | ||
allowDataAttributes(attributes?: string[]): this; | ||
/** | ||
@@ -124,5 +125,14 @@ * Preserves style attributes. Note that the sanitizer won't parse and | ||
private transitionsAllowed; | ||
private openShadow; | ||
allowAnimations(): this; | ||
allowTransitions(): this; | ||
/** | ||
* Sets the shadow DOM mode to 'open'. | ||
* | ||
* While this method is not formally restricted, it can potentially be used to | ||
* bypass the security guarantees of the CSS sanitizer. If you need open | ||
* shadow DOM, please contact ise-web-members@ to discuss your use case. | ||
*/ | ||
withOpenShadow(): this; | ||
/** | ||
* Builds a CSS sanitizer. | ||
@@ -129,0 +139,0 @@ * |
@@ -39,3 +39,3 @@ /** | ||
} | ||
this.sanitizerTable = new SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -67,3 +67,3 @@ } | ||
} | ||
this.sanitizerTable = new SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(allowedElements, allowedElementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -97,9 +97,10 @@ } | ||
} | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, elementPolicies, allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, elementPolicies, allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
} | ||
/** | ||
* Allows the set of data attributes passed. | ||
* Allows all or a definite set of data attributes passed. | ||
* | ||
* These values must be prefixed with "data-" | ||
* When called without arguments, all data attributes are allowed. | ||
* When a set of attributes is passed, its values must be prefixed with "data-" | ||
* | ||
@@ -110,2 +111,8 @@ * If called with onlyAllowElements or onlyAllowAttributes, those methods must | ||
allowDataAttributes(attributes) { | ||
if (attributes === undefined) { | ||
const globallyAllowedAttributePrefixes = new Set(this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
globallyAllowedAttributePrefixes.add('data-'); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, globallyAllowedAttributePrefixes); | ||
return this; | ||
} | ||
const allowedGlobalAttributes = new Set(this.sanitizerTable.allowedGlobalAttributes); | ||
@@ -118,3 +125,3 @@ for (const attribute of attributes) { | ||
} | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -134,3 +141,3 @@ } | ||
}); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, this.sanitizerTable.allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -146,3 +153,3 @@ } | ||
allowedGlobalAttributes.add('class'); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -157,3 +164,3 @@ } | ||
allowedGlobalAttributes.add('id'); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -177,3 +184,3 @@ } | ||
.add('list'); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(this.sanitizerTable.allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, this.sanitizerTable.globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
return this; | ||
@@ -248,2 +255,3 @@ } | ||
this.transitionsAllowed = false; | ||
this.openShadow = false; | ||
} | ||
@@ -259,2 +267,13 @@ allowAnimations() { | ||
/** | ||
* Sets the shadow DOM mode to 'open'. | ||
* | ||
* While this method is not formally restricted, it can potentially be used to | ||
* bypass the security guarantees of the CSS sanitizer. If you need open | ||
* shadow DOM, please contact ise-web-members@ to discuss your use case. | ||
*/ | ||
withOpenShadow() { | ||
this.openShadow = true; | ||
return this; | ||
} | ||
/** | ||
* Builds a CSS sanitizer. | ||
@@ -276,3 +295,3 @@ * | ||
const styleAttributeSanitizer = (cssText) => sanitizeStyleAttribute(cssText, CSS_PROPERTY_ALLOWLIST, CSS_FUNCTION_ALLOWLIST, this.resourceUrlPolicy, propertyDiscarders); | ||
return new HtmlSanitizerImpl(this.sanitizerTable, secretToken, styleElementSanitizer, styleAttributeSanitizer, this.resourceUrlPolicy); | ||
return new HtmlSanitizerImpl(this.sanitizerTable, secretToken, styleElementSanitizer, styleAttributeSanitizer, this.resourceUrlPolicy, this.openShadow); | ||
} | ||
@@ -290,4 +309,4 @@ extendSanitizerTableForCss() { | ||
allowedGlobalAttributes.add('class'); | ||
this.sanitizerTable = new SanitizerTable(allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, globalAttributePolicies); | ||
this.sanitizerTable = new SanitizerTable(allowedElements, this.sanitizerTable.elementPolicies, allowedGlobalAttributes, globalAttributePolicies, this.sanitizerTable.globallyAllowedAttributePrefixes); | ||
} | ||
} |
@@ -49,4 +49,5 @@ /** | ||
private readonly resourceUrlPolicy?; | ||
private readonly openShadow?; | ||
private changes; | ||
constructor(sanitizerTable: SanitizerTable, token: object, styleElementSanitizer?: CssSanitizationFn | undefined, styleAttributeSanitizer?: CssSanitizationFn | undefined, resourceUrlPolicy?: ResourceUrlPolicy | undefined); | ||
constructor(sanitizerTable: SanitizerTable, token: object, styleElementSanitizer?: CssSanitizationFn | undefined, styleAttributeSanitizer?: CssSanitizationFn | undefined, resourceUrlPolicy?: ResourceUrlPolicy | undefined, openShadow?: boolean | undefined); | ||
sanitizeAssertUnchanged(html: string): SafeHtml; | ||
@@ -53,0 +54,0 @@ sanitize(html: string): SafeHtml; |
@@ -19,3 +19,3 @@ /** | ||
export class HtmlSanitizerImpl { | ||
constructor(sanitizerTable, token, styleElementSanitizer, styleAttributeSanitizer, resourceUrlPolicy) { | ||
constructor(sanitizerTable, token, styleElementSanitizer, styleAttributeSanitizer, resourceUrlPolicy, openShadow) { | ||
this.sanitizerTable = sanitizerTable; | ||
@@ -25,2 +25,3 @@ this.styleElementSanitizer = styleElementSanitizer; | ||
this.resourceUrlPolicy = resourceUrlPolicy; | ||
this.openShadow = openShadow; | ||
this.changes = []; | ||
@@ -54,3 +55,4 @@ ensureTokenIsValid(token); | ||
const elem = document.createElement('safevalues-with-css'); | ||
const shadow = elem.attachShadow({ mode: 'closed' }); | ||
const mode = this.openShadow ? 'open' : 'closed'; | ||
const shadow = elem.attachShadow({ mode }); | ||
const sanitized = this.sanitizeToFragmentInternal(htmlWithCss, inertDocument); | ||
@@ -57,0 +59,0 @@ const internalStyle = document.createElement('style'); |
@@ -268,2 +268,3 @@ /** | ||
'checked', | ||
'cite', | ||
'color', | ||
@@ -273,2 +274,3 @@ 'cols', | ||
'controls', | ||
'controlslist', | ||
'datetime', | ||
@@ -299,2 +301,3 @@ 'disabled', | ||
'placeholder', | ||
'poster', | ||
'preload', | ||
@@ -353,8 +356,2 @@ 'rel', | ||
[ | ||
'cite', | ||
{ | ||
policyAction: AttributePolicyAction.KEEP_AND_SANITIZE_URL, | ||
}, | ||
], | ||
[ | ||
'loading', | ||
@@ -371,8 +368,2 @@ { | ||
[ | ||
'poster', | ||
{ | ||
policyAction: AttributePolicyAction.KEEP_AND_SANITIZE_URL, | ||
}, | ||
], | ||
[ | ||
'target', | ||
@@ -393,2 +384,2 @@ { | ||
*/ | ||
export const DEFAULT_SANITIZER_TABLE = new SanitizerTable(new Set(ALLOWED_ELEMENTS), new Map(ELEMENT_POLICIES), new Set(ALLOWED_GLOBAL_ATTRIBUTES), new Map(GLOBAL_ATTRIBUTE_POLICIES)); | ||
export const DEFAULT_SANITIZER_TABLE = new SanitizerTable(new Set(ALLOWED_ELEMENTS), new Map(ELEMENT_POLICIES), new Set(ALLOWED_GLOBAL_ATTRIBUTES), new Map(GLOBAL_ATTRIBUTE_POLICIES), undefined); |
@@ -12,4 +12,4 @@ /** | ||
readonly globalAttributePolicies: ReadonlyMap<string, AttributePolicy>; | ||
readonly globallyAllowedAttributePrefixes?: ReadonlySet<string> | undefined; | ||
constructor(allowedElements: ReadonlySet<string>, elementPolicies: ReadonlyMap<string, ElementPolicy>, allowedGlobalAttributes: ReadonlySet<string>, globalAttributePolicies: ReadonlyMap<string, AttributePolicy>, globallyAllowedAttributePrefixes?: ReadonlySet<string> | undefined); | ||
readonly globallyAllowedAttributePrefixes: ReadonlySet<string> | undefined; | ||
constructor(allowedElements: ReadonlySet<string>, elementPolicies: ReadonlyMap<string, ElementPolicy>, allowedGlobalAttributes: ReadonlySet<string>, globalAttributePolicies: ReadonlyMap<string, AttributePolicy>, globallyAllowedAttributePrefixes: ReadonlySet<string> | undefined); | ||
isAllowedElement(elementName: string): boolean; | ||
@@ -16,0 +16,0 @@ getAttributePolicy(attributeName: string, elementName: string): AttributePolicy; |
@@ -10,2 +10,2 @@ /** | ||
*/ | ||
export declare const SECURITY_SENSITIVE_ATTRIBUTES: readonly ["src", "srcdoc", "codebase", "data", "href", "rel", "action", "formaction", "sandbox", "cite", "poster", "icon"]; | ||
export declare const SECURITY_SENSITIVE_ATTRIBUTES: readonly ["src", "srcdoc", "codebase", "data", "href", "rel", "action", "formaction", "sandbox", "icon"]; |
@@ -21,5 +21,3 @@ /** | ||
'sandbox', | ||
'cite', | ||
'poster', | ||
'icon', | ||
]; |
@@ -14,2 +14,3 @@ /** | ||
import { SafeHtml } from '../../internals/html_impl.js'; | ||
import { TrustedResourceUrl } from '../../internals/resource_url_impl.js'; | ||
declare type ScriptOrStyle = HTMLScriptElement | HTMLStyleElement | SVGScriptElement | SVGStyleElement; | ||
@@ -42,3 +43,3 @@ /** | ||
/** | ||
* The safe alternative to Element#setAttribute. The function takes a list of | ||
* A safe alternative to Element#setAttribute. The function takes a list of | ||
* `SafeAttributePrefix`, making developer intention explicit. The attribute | ||
@@ -49,2 +50,45 @@ * to be set must has one of the safe prefixes, otherwise the function throws | ||
export declare function setElementPrefixedAttribute(attrPrefixes: readonly SafeAttributePrefix[], e: Element, attr: string, value: string): void; | ||
/** | ||
* A safe alternative to Element#setAttribute. | ||
* | ||
* The function has essentially the same signature as `Element.setAttribute`, | ||
* but requires a safe type (or sanitizes the value) when used with a security | ||
* sensitive attribute. It does this by forwarding the call to the | ||
* element-specific setters within `safevalues/dom`. | ||
* | ||
* Note that this function doesn't currently support elements outside of the | ||
* html namespace & might throw if used with the wrong type of element or | ||
* attribute value | ||
* | ||
* If code size is a concern, consider using `setPrefixedAttribute`, or the | ||
* element-specific setters. | ||
* | ||
* The security sensitive element/attributes pairs are the following: | ||
* - anchor#href -> forwarded to `setAnchorHref` | ||
* - area#href -> forwarded to `setAreaHref` | ||
* - base#href -> forwarded to `setBaseHref` | ||
* - button#formaction -> forwarded to `setButtonFormaction` | ||
* - embed#src -> forwarded to `setEmbedSrc` | ||
* - form#action -> forwarded to `setFormAction` | ||
* - iframe#src -> forwarded to `setIframeSrc` | ||
* - iframe#srcdoc -> forwarded to `setIframeSrcdoc` | ||
* - iframe#sandbox -> rejected, use `setIframeSrcWithIntent` or | ||
* `setIframeSrcdocWithIntent` instead | ||
* - input#formaction -> forwarded to `setInputFormaction` | ||
* - link#href -> rejected, use `setLinkHrefAndRel` instead | ||
* - link#rel -> rejected, use `setLinkHrefAndRel` instead | ||
* - object#data -> forwarded to `setObjectData` | ||
* - script#src -> forwarded to `setScriptSrc` | ||
* - global attributes: | ||
* - target -> forwarded to `el.setAttribute` | ||
* - cite -> forwarded to `el.setAttribute` | ||
* - poster -> forwarded to `el.setAttribute` | ||
* - srcset -> forwarded to `el.setAttribute` | ||
* - src -> forwarded to `el.setAttribute` | ||
* - href -> forwarded to `el.setAttribute` | ||
* - any attribute starting with `on` -> rejected | ||
* | ||
* Every other attribute is set as is using `element.setAttribute` | ||
*/ | ||
export declare function setElementAttribute(el: HTMLElement, attr: string, value: string | TrustedResourceUrl | SafeHtml): void; | ||
export {}; |
@@ -14,2 +14,12 @@ /** | ||
import { unwrapHtml } from '../../internals/html_impl.js'; | ||
import { setAnchorHref } from './anchor.js'; | ||
import { setAreaHref } from './area.js'; | ||
import { setBaseHref } from './base.js'; | ||
import { setButtonFormaction } from './button.js'; | ||
import { setEmbedSrc } from './embed.js'; | ||
import { setFormAction } from './form.js'; | ||
import { setIframeSrc, setIframeSrcdoc } from './iframe.js'; | ||
import { setInputFormaction } from './input.js'; | ||
import { setObjectData } from './object.js'; | ||
import { setScriptSrc } from './script.js'; | ||
/** | ||
@@ -65,3 +75,3 @@ * Safely set {@link Element.innerHTML} on a given ShadowRoot or Element which | ||
/** | ||
* The safe alternative to Element#setAttribute. The function takes a list of | ||
* A safe alternative to Element#setAttribute. The function takes a list of | ||
* `SafeAttributePrefix`, making developer intention explicit. The attribute | ||
@@ -104,1 +114,101 @@ * to be set must has one of the safe prefixes, otherwise the function throws | ||
} | ||
/** | ||
* A safe alternative to Element#setAttribute. | ||
* | ||
* The function has essentially the same signature as `Element.setAttribute`, | ||
* but requires a safe type (or sanitizes the value) when used with a security | ||
* sensitive attribute. It does this by forwarding the call to the | ||
* element-specific setters within `safevalues/dom`. | ||
* | ||
* Note that this function doesn't currently support elements outside of the | ||
* html namespace & might throw if used with the wrong type of element or | ||
* attribute value | ||
* | ||
* If code size is a concern, consider using `setPrefixedAttribute`, or the | ||
* element-specific setters. | ||
* | ||
* The security sensitive element/attributes pairs are the following: | ||
* - anchor#href -> forwarded to `setAnchorHref` | ||
* - area#href -> forwarded to `setAreaHref` | ||
* - base#href -> forwarded to `setBaseHref` | ||
* - button#formaction -> forwarded to `setButtonFormaction` | ||
* - embed#src -> forwarded to `setEmbedSrc` | ||
* - form#action -> forwarded to `setFormAction` | ||
* - iframe#src -> forwarded to `setIframeSrc` | ||
* - iframe#srcdoc -> forwarded to `setIframeSrcdoc` | ||
* - iframe#sandbox -> rejected, use `setIframeSrcWithIntent` or | ||
* `setIframeSrcdocWithIntent` instead | ||
* - input#formaction -> forwarded to `setInputFormaction` | ||
* - link#href -> rejected, use `setLinkHrefAndRel` instead | ||
* - link#rel -> rejected, use `setLinkHrefAndRel` instead | ||
* - object#data -> forwarded to `setObjectData` | ||
* - script#src -> forwarded to `setScriptSrc` | ||
* - global attributes: | ||
* - target -> forwarded to `el.setAttribute` | ||
* - cite -> forwarded to `el.setAttribute` | ||
* - poster -> forwarded to `el.setAttribute` | ||
* - srcset -> forwarded to `el.setAttribute` | ||
* - src -> forwarded to `el.setAttribute` | ||
* - href -> forwarded to `el.setAttribute` | ||
* - any attribute starting with `on` -> rejected | ||
* | ||
* Every other attribute is set as is using `element.setAttribute` | ||
*/ | ||
export function setElementAttribute(el, attr, value) { | ||
if (el.namespaceURI !== 'http://www.w3.org/1999/xhtml') { | ||
throw new Error(`Cannot set attribute '${attr}' on '${el.tagName}'.` + | ||
`Element is not in the HTML namespace`); | ||
} | ||
attr = attr.toLowerCase(); | ||
const key = `${el.tagName} ${attr}`; | ||
switch (key) { | ||
case 'A href': | ||
setAnchorHref(el, value); | ||
return; | ||
case 'AREA href': | ||
setAreaHref(el, value); | ||
return; | ||
case 'BASE href': | ||
setBaseHref(el, value); | ||
return; | ||
case 'BUTTON formaction': | ||
setButtonFormaction(el, value); | ||
return; | ||
case 'EMBED src': | ||
setEmbedSrc(el, value); | ||
return; | ||
case 'FORM action': | ||
setFormAction(el, value); | ||
return; | ||
case 'IFRAME src': | ||
setIframeSrc(el, value); | ||
return; | ||
case 'IFRAME srcdoc': | ||
setIframeSrcdoc(el, value); | ||
return; | ||
case 'IFRAME sandbox': | ||
throw new Error("Can't set 'sandbox' on iframe tags. " + | ||
'Use setIframeSrcWithIntent or setIframeSrcdocWithIntent instead'); | ||
case 'INPUT formaction': | ||
setInputFormaction(el, value); | ||
return; | ||
case 'LINK href': | ||
throw new Error("Can't set 'href' attribute on link tags. " + | ||
'Use setLinkHrefAndRel instead'); | ||
case 'LINK rel': | ||
throw new Error("Can't set 'rel' attribute on link tags. " + | ||
'Use setLinkHrefAndRel instead'); | ||
case 'OBJECT data': | ||
setObjectData(el, value); | ||
return; | ||
case 'SCRIPT src': | ||
setScriptSrc(el, value); | ||
return; | ||
default: | ||
if (/^on./.test(attr)) { | ||
throw new Error(`Attribute "${attr}" looks like an event handler attribute. ` + | ||
`Please use a safe alternative like addEventListener instead.`); | ||
} | ||
el.setAttribute(attr, value); | ||
} | ||
} |
@@ -14,3 +14,3 @@ /** | ||
export { setButtonFormaction } from './elements/button.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementAttribute, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { setEmbedSrc } from './elements/embed.js'; | ||
@@ -17,0 +17,0 @@ export { setFormAction } from './elements/form.js'; |
@@ -14,3 +14,3 @@ /** | ||
export { setButtonFormaction } from './elements/button.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { buildPrefixedAttributeSetter, elementInsertAdjacentHtml, setElementAttribute, setElementInnerHtml, setElementOuterHtml, setElementPrefixedAttribute, } from './elements/element.js'; | ||
export { setEmbedSrc } from './elements/embed.js'; | ||
@@ -17,0 +17,0 @@ export { setFormAction } from './elements/form.js'; |
{ | ||
"type": "module", | ||
"version": "1.0.1" | ||
"version": "1.1.0" | ||
} |
{ | ||
"name": "safevalues", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Safe builders for Trusted Types values", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/google/safevalues", |
602850
15251