@locker/trusted-types
Advanced tools
Comparing version 0.18.12 to 0.18.13
@@ -8,23 +8,223 @@ /*! | ||
value: true | ||
}); // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types | ||
}); | ||
const createPolicy = (name, options) => // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
typeof trustedTypes === 'undefined' ? // istanbul ignore next: currently unreachable via tests (trustedTypes never undefined) | ||
options : // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
trustedTypes.createPolicy(name, options); | ||
var htmlSanitizer = require('@locker/html-sanitizer'); | ||
const defaults = { | ||
createHTML: function (value) { | ||
var shared = require('@locker/shared'); | ||
var sharedDom = require('@locker/shared-dom'); | ||
var sharedUrl = require('@locker/shared-url'); | ||
const inflightRequests = shared.toSafeWeakMap(new shared.WeakMapCtor()); | ||
async function getSourceText(resourceURL, targetElement) { | ||
abortInFlightRequest(targetElement); | ||
const controller = new sharedDom.AbortControllerCtor(); | ||
const signal = shared.ReflectApply(sharedDom.AbortControllerProtoSignalGetter, controller, []); | ||
inflightRequests.set(targetElement, controller); | ||
const response = await sharedDom.WindowFetch(resourceURL, { | ||
__proto__: null, | ||
method: 'GET', | ||
credentials: 'include', | ||
signal | ||
}); | ||
inflightRequests.delete(targetElement); | ||
if (!shared.ReflectApply(sharedDom.ResponseProtoOkGetter, response, [])) { | ||
throw new shared.ErrorCtor('Request failed.'); | ||
} | ||
const sourceText = await shared.ReflectApply(sharedDom.ResponseProtoText, response, []); | ||
return sourceText; | ||
} | ||
function abortInFlightRequest(element) { | ||
const abortController = inflightRequests.get(element); | ||
if (abortController) { | ||
shared.ReflectApply(sharedDom.AbortControllerProtoAbort, abortController, []); | ||
} | ||
} | ||
const EVALUATOR_PROPERTY_KEY = '$evaluator$'; | ||
const BLOB_SCRIPT_SOURCE = `document.currentScript['${EVALUATOR_PROPERTY_KEY}']`; // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
const SUPPORTS_TRUSTED_TYPES = typeof trustedTypes !== 'undefined'; | ||
function createTrustedTypesPolicy(name, options) { | ||
// @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
return trustedTypes.createPolicy(name, options); | ||
} | ||
function createFallbackPolicy(_name, options) { | ||
return options; | ||
} // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types | ||
const createPolicy = SUPPORTS_TRUSTED_TYPES ? createTrustedTypesPolicy : createFallbackPolicy; | ||
const policyOptions$1 = { | ||
createHTML(value) { | ||
return value; | ||
}, | ||
createScript: function (value) { | ||
createScript(value) { | ||
return value; | ||
}, | ||
createScriptURL: function (value) { | ||
createScriptURL(value) { | ||
return value; | ||
} | ||
}; | ||
const trusted = createPolicy('trusted', defaults); | ||
exports.createPolicy = createPolicy; | ||
const trusted = createPolicy('trusted', policyOptions$1); | ||
const evaluatedScripts = shared.toSafeWeakSet(new shared.WeakSetCtor()); | ||
const scriptURLsCache = shared.toSafeWeakMap(new shared.WeakMapCtor()); | ||
const policyOptions = { | ||
createHTML(dirty, lwsKey, contentType) { | ||
if (dirty === null || dirty === undefined) { | ||
return ''; | ||
} | ||
switch (contentType) { | ||
case 0 | ||
/* ContentType.HTML */ | ||
: | ||
return htmlSanitizer.sanitize(dirty, lwsKey); | ||
case 1 | ||
/* ContentType.SVG */ | ||
: | ||
return ''; | ||
case 2 | ||
/* ContentType.XML */ | ||
: | ||
return dirty; | ||
default: | ||
return ''; | ||
} | ||
}, | ||
createScript(_dirty, _evaluator) { | ||
return ''; | ||
}, | ||
createScriptURL(dirty, evaluator, targetElement) { | ||
const setURL = encloseSrcSetter(targetElement); | ||
dirty = `${dirty}`; // Passthrough for any script element evaluated by us | ||
// or if userland code tries to set a falsy value. | ||
if (evaluatedScripts.has(targetElement) || dirty === '' || dirty === 'undefined' || dirty === 'null') { | ||
setURL(trusted.createScriptURL(dirty)); | ||
return dirty; | ||
} | ||
const targetElementIsConnected = shared.ReflectApply(sharedDom.NodeProtoIsConnectedGetter, targetElement, []); | ||
const resolvedURL = sharedUrl.resolveURL(dirty); | ||
if (targetElementIsConnected) { | ||
// When the script is connected and has a .src value it is safe to let the url passthrough | ||
// because it will never be evaluated again. | ||
if (getURL(targetElement)) { | ||
evaluatedScripts.add(targetElement); | ||
setURL(trusted.createScriptURL(dirty)); | ||
return dirty; | ||
} // There is a small window while the source code is asynchronously fetched but the script may | ||
// have already been placed in the DOM without having yet our blob URL set as the .src value. | ||
// We block the request in this scenario and set the last URL after we evaluate. | ||
if (scriptURLsCache.has(targetElement)) { | ||
return ''; | ||
} | ||
} | ||
const asyncRequest = getSourceText(resolvedURL, targetElement); | ||
scriptURLsCache.set(targetElement, resolvedURL); | ||
const safeURL = createSandboxURL(); | ||
const onFulfill = sourceText => { | ||
shared.ReflectDefineProperty(targetElement, EVALUATOR_PROPERTY_KEY, { | ||
__proto__: null, | ||
configurable: true, | ||
get: shared.ReflectApply(shared.FunctionProtoBind, () => { | ||
shared.ReflectDeleteProperty(targetElement, EVALUATOR_PROPERTY_KEY); | ||
sharedDom.URLRevokeObjectURL(safeURL); | ||
const cachedURL = scriptURLsCache.get(targetElement); | ||
scriptURLsCache.delete(targetElement); | ||
evaluatedScripts.add(targetElement); // We sign & assign the original URL even though it will not be executed. | ||
// The wrappedEvaluator is guaranteed to run only one time once the script | ||
// is appended in the dom. | ||
// Re-assigning .src after it ran will not retrigger the evaluation | ||
// of the new URL. | ||
// However, TrustedTypes still requires this assignment to be signed. | ||
// We do this because we don't want to leave observable traces in the DOM. | ||
setURL(trusted.createScriptURL(cachedURL)); | ||
evaluator(sourceText); | ||
}, [targetElement]), | ||
set: undefined | ||
}); | ||
setURL(trusted.createScriptURL(safeURL)); | ||
}; | ||
const onReject = _error => { | ||
sharedDom.URLRevokeObjectURL(safeURL); | ||
const cachedURL = scriptURLsCache.get(targetElement); | ||
scriptURLsCache.delete(targetElement); // We are only able to generate 404 errors and we cannot trust any other URL. | ||
// This blob URL will be sufficient to trigger error event handlers. | ||
// We still have to sign this URL, TrustedTypes does not take into consideration | ||
// the state of the script elements. It's an either or operation: either we set a | ||
// signed value and we are ok or we don't and the browser throws an error. We | ||
// want our 404 URL to be set and trigger the event handlers, hence we have to sign. | ||
setURL(trusted.createScriptURL('blob:http://localhost/not-found')); // This error event handler will get triggered after we set our 404 blob URL. | ||
const errorEventHandler = () => { | ||
// Similar to our wrappedEvaluator, we leave no traces. | ||
setURL(trusted.createScriptURL(cachedURL)); | ||
shared.ReflectApply(sharedDom.EventTargetProtoRemoveEventListener, targetElement, ['error', errorEventHandler]); | ||
}; | ||
shared.ReflectApply(sharedDom.EventTargetProtoAddEventListener, targetElement, ['error', errorEventHandler]); | ||
}; | ||
shared.ReflectApply(shared.PromiseProtoThen, asyncRequest, [onFulfill, onReject]); | ||
return ''; | ||
} | ||
}; | ||
const lwsInternalPolicy = createPolicy('lwsInternal', policyOptions); // Even though the content is always the same we use unique URLs for each script. | ||
function createSandboxURL() { | ||
return sharedDom.URLCreateObjectURL(new sharedDom.BlobCtor([BLOB_SCRIPT_SOURCE], { | ||
__proto__: null, | ||
type: 'text/javascript' | ||
})); | ||
} | ||
function getURL(targetElement) { | ||
const isHTMLScriptElement = targetElement instanceof sharedDom.HTMLScriptElementCtor; | ||
if (isHTMLScriptElement) { | ||
return shared.ReflectApply(sharedDom.ElementProtoGetAttribute, targetElement, ['src']); | ||
} | ||
const hasHref = shared.ReflectApply(sharedDom.ElementProtoHasAttribute, targetElement, ['href']); | ||
return hasHref ? shared.ReflectApply(sharedDom.ElementProtoGetAttribute, targetElement, ['href']) : shared.ReflectApply(sharedDom.ElementProtoGetAttribute, targetElement, ['xlink:href']); | ||
} | ||
function encloseSrcSetter(targetElement) { | ||
const namespaceURI = shared.ReflectApply(sharedDom.ElementProtoNamespaceURIGetter, targetElement, []); | ||
const attributeNamespaceURI = namespaceURI === sharedDom.NAMESPACE_XHTML ? '' : sharedDom.NAMESPACE_XLINK; | ||
const attributeName = targetElement instanceof sharedDom.HTMLScriptElementCtor ? 'src' : 'href'; | ||
return function (src) { | ||
shared.ReflectApply(sharedDom.ElementProtoSetAttributeNS, targetElement, [attributeNamespaceURI, attributeName, src]); | ||
}; | ||
} | ||
exports.lwsInternalPolicy = lwsInternalPolicy; | ||
exports.trusted = trusted; | ||
/*! version: 0.18.12 */ | ||
/*! version: 0.18.13 */ |
/*! | ||
* Copyright (C) 2023 salesforce.com, inc. | ||
*/ | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types | ||
const createPolicy = (name, options) => // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
typeof trustedTypes === 'undefined' ? // istanbul ignore next: currently unreachable via tests (trustedTypes never undefined) | ||
options : // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
trustedTypes.createPolicy(name, options); | ||
import { sanitize } from '@locker/html-sanitizer'; | ||
import { toSafeWeakMap, WeakMapCtor, ReflectApply, ErrorCtor, toSafeWeakSet, WeakSetCtor, PromiseProtoThen, ReflectDefineProperty, FunctionProtoBind, ReflectDeleteProperty } from '@locker/shared'; | ||
import { AbortControllerCtor, AbortControllerProtoSignalGetter, WindowFetch, ResponseProtoOkGetter, ResponseProtoText, AbortControllerProtoAbort, NodeProtoIsConnectedGetter, URLCreateObjectURL, BlobCtor, ElementProtoGetAttribute, ElementProtoHasAttribute, ElementProtoNamespaceURIGetter, ElementProtoSetAttributeNS, URLRevokeObjectURL, EventTargetProtoAddEventListener, HTMLScriptElementCtor, NAMESPACE_XHTML, NAMESPACE_XLINK, EventTargetProtoRemoveEventListener } from '@locker/shared-dom'; | ||
import { resolveURL } from '@locker/shared-url'; | ||
const inflightRequests = toSafeWeakMap(new WeakMapCtor()); | ||
const defaults = { | ||
createHTML: function (value) { | ||
async function getSourceText(resourceURL, targetElement) { | ||
abortInFlightRequest(targetElement); | ||
const controller = new AbortControllerCtor(); | ||
const signal = ReflectApply(AbortControllerProtoSignalGetter, controller, []); | ||
inflightRequests.set(targetElement, controller); | ||
const response = await WindowFetch(resourceURL, { | ||
__proto__: null, | ||
method: 'GET', | ||
credentials: 'include', | ||
signal | ||
}); | ||
inflightRequests.delete(targetElement); | ||
if (!ReflectApply(ResponseProtoOkGetter, response, [])) { | ||
throw new ErrorCtor('Request failed.'); | ||
} | ||
const sourceText = await ReflectApply(ResponseProtoText, response, []); | ||
return sourceText; | ||
} | ||
function abortInFlightRequest(element) { | ||
const abortController = inflightRequests.get(element); | ||
if (abortController) { | ||
ReflectApply(AbortControllerProtoAbort, abortController, []); | ||
} | ||
} | ||
const EVALUATOR_PROPERTY_KEY = '$evaluator$'; | ||
const BLOB_SCRIPT_SOURCE = `document.currentScript['${EVALUATOR_PROPERTY_KEY}']`; // @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
const SUPPORTS_TRUSTED_TYPES = typeof trustedTypes !== 'undefined'; | ||
function createTrustedTypesPolicy(name, options) { | ||
// @ts-ignore: Prevent cannot find name 'trustedTypes' error. | ||
return trustedTypes.createPolicy(name, options); | ||
} | ||
function createFallbackPolicy(_name, options) { | ||
return options; | ||
} // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types | ||
const createPolicy = SUPPORTS_TRUSTED_TYPES ? createTrustedTypesPolicy : createFallbackPolicy; | ||
const policyOptions$1 = { | ||
createHTML(value) { | ||
return value; | ||
}, | ||
createScript: function (value) { | ||
createScript(value) { | ||
return value; | ||
}, | ||
createScriptURL: function (value) { | ||
createScriptURL(value) { | ||
return value; | ||
} | ||
}; | ||
const trusted = createPolicy('trusted', defaults); | ||
export { createPolicy, trusted }; | ||
/*! version: 0.18.12 */ | ||
const trusted = createPolicy('trusted', policyOptions$1); | ||
const evaluatedScripts = toSafeWeakSet(new WeakSetCtor()); | ||
const scriptURLsCache = toSafeWeakMap(new WeakMapCtor()); | ||
const policyOptions = { | ||
createHTML(dirty, lwsKey, contentType) { | ||
if (dirty === null || dirty === undefined) { | ||
return ''; | ||
} | ||
switch (contentType) { | ||
case 0 | ||
/* ContentType.HTML */ | ||
: | ||
return sanitize(dirty, lwsKey); | ||
case 1 | ||
/* ContentType.SVG */ | ||
: | ||
return ''; | ||
case 2 | ||
/* ContentType.XML */ | ||
: | ||
return dirty; | ||
default: | ||
return ''; | ||
} | ||
}, | ||
createScript(_dirty, _evaluator) { | ||
return ''; | ||
}, | ||
createScriptURL(dirty, evaluator, targetElement) { | ||
const setURL = encloseSrcSetter(targetElement); | ||
dirty = `${dirty}`; // Passthrough for any script element evaluated by us | ||
// or if userland code tries to set a falsy value. | ||
if (evaluatedScripts.has(targetElement) || dirty === '' || dirty === 'undefined' || dirty === 'null') { | ||
setURL(trusted.createScriptURL(dirty)); | ||
return dirty; | ||
} | ||
const targetElementIsConnected = ReflectApply(NodeProtoIsConnectedGetter, targetElement, []); | ||
const resolvedURL = resolveURL(dirty); | ||
if (targetElementIsConnected) { | ||
// When the script is connected and has a .src value it is safe to let the url passthrough | ||
// because it will never be evaluated again. | ||
if (getURL(targetElement)) { | ||
evaluatedScripts.add(targetElement); | ||
setURL(trusted.createScriptURL(dirty)); | ||
return dirty; | ||
} // There is a small window while the source code is asynchronously fetched but the script may | ||
// have already been placed in the DOM without having yet our blob URL set as the .src value. | ||
// We block the request in this scenario and set the last URL after we evaluate. | ||
if (scriptURLsCache.has(targetElement)) { | ||
return ''; | ||
} | ||
} | ||
const asyncRequest = getSourceText(resolvedURL, targetElement); | ||
scriptURLsCache.set(targetElement, resolvedURL); | ||
const safeURL = createSandboxURL(); | ||
const onFulfill = sourceText => { | ||
ReflectDefineProperty(targetElement, EVALUATOR_PROPERTY_KEY, { | ||
__proto__: null, | ||
configurable: true, | ||
get: ReflectApply(FunctionProtoBind, () => { | ||
ReflectDeleteProperty(targetElement, EVALUATOR_PROPERTY_KEY); | ||
URLRevokeObjectURL(safeURL); | ||
const cachedURL = scriptURLsCache.get(targetElement); | ||
scriptURLsCache.delete(targetElement); | ||
evaluatedScripts.add(targetElement); // We sign & assign the original URL even though it will not be executed. | ||
// The wrappedEvaluator is guaranteed to run only one time once the script | ||
// is appended in the dom. | ||
// Re-assigning .src after it ran will not retrigger the evaluation | ||
// of the new URL. | ||
// However, TrustedTypes still requires this assignment to be signed. | ||
// We do this because we don't want to leave observable traces in the DOM. | ||
setURL(trusted.createScriptURL(cachedURL)); | ||
evaluator(sourceText); | ||
}, [targetElement]), | ||
set: undefined | ||
}); | ||
setURL(trusted.createScriptURL(safeURL)); | ||
}; | ||
const onReject = _error => { | ||
URLRevokeObjectURL(safeURL); | ||
const cachedURL = scriptURLsCache.get(targetElement); | ||
scriptURLsCache.delete(targetElement); // We are only able to generate 404 errors and we cannot trust any other URL. | ||
// This blob URL will be sufficient to trigger error event handlers. | ||
// We still have to sign this URL, TrustedTypes does not take into consideration | ||
// the state of the script elements. It's an either or operation: either we set a | ||
// signed value and we are ok or we don't and the browser throws an error. We | ||
// want our 404 URL to be set and trigger the event handlers, hence we have to sign. | ||
setURL(trusted.createScriptURL('blob:http://localhost/not-found')); // This error event handler will get triggered after we set our 404 blob URL. | ||
const errorEventHandler = () => { | ||
// Similar to our wrappedEvaluator, we leave no traces. | ||
setURL(trusted.createScriptURL(cachedURL)); | ||
ReflectApply(EventTargetProtoRemoveEventListener, targetElement, ['error', errorEventHandler]); | ||
}; | ||
ReflectApply(EventTargetProtoAddEventListener, targetElement, ['error', errorEventHandler]); | ||
}; | ||
ReflectApply(PromiseProtoThen, asyncRequest, [onFulfill, onReject]); | ||
return ''; | ||
} | ||
}; | ||
const lwsInternalPolicy = createPolicy('lwsInternal', policyOptions); // Even though the content is always the same we use unique URLs for each script. | ||
function createSandboxURL() { | ||
return URLCreateObjectURL(new BlobCtor([BLOB_SCRIPT_SOURCE], { | ||
__proto__: null, | ||
type: 'text/javascript' | ||
})); | ||
} | ||
function getURL(targetElement) { | ||
const isHTMLScriptElement = targetElement instanceof HTMLScriptElementCtor; | ||
if (isHTMLScriptElement) { | ||
return ReflectApply(ElementProtoGetAttribute, targetElement, ['src']); | ||
} | ||
const hasHref = ReflectApply(ElementProtoHasAttribute, targetElement, ['href']); | ||
return hasHref ? ReflectApply(ElementProtoGetAttribute, targetElement, ['href']) : ReflectApply(ElementProtoGetAttribute, targetElement, ['xlink:href']); | ||
} | ||
function encloseSrcSetter(targetElement) { | ||
const namespaceURI = ReflectApply(ElementProtoNamespaceURIGetter, targetElement, []); | ||
const attributeNamespaceURI = namespaceURI === NAMESPACE_XHTML ? '' : NAMESPACE_XLINK; | ||
const attributeName = targetElement instanceof HTMLScriptElementCtor ? 'src' : 'href'; | ||
return function (src) { | ||
ReflectApply(ElementProtoSetAttributeNS, targetElement, [attributeNamespaceURI, attributeName, src]); | ||
}; | ||
} | ||
export { lwsInternalPolicy, trusted }; | ||
/*! version: 0.18.13 */ |
{ | ||
"name": "@locker/trusted-types", | ||
"version": "0.18.12", | ||
"version": "0.18.13", | ||
"license": "SEE LICENSE IN LICENSE.txt", | ||
@@ -23,3 +23,8 @@ "author": "Salesforce UI Security Team", | ||
], | ||
"gitHead": "c77e7a4fd162647dd8828972c09cee4e9c7096d5" | ||
"dependencies": { | ||
"@locker/html-sanitizer": "0.18.13", | ||
"@locker/shared": "0.18.13", | ||
"@locker/shared-dom": "0.18.13", | ||
"@locker/shared-url": "0.18.13" | ||
} | ||
} |
@@ -1,8 +0,4 @@ | ||
export declare type PolicyOptions = Object & { | ||
createHTML: Function; | ||
createScript: Function; | ||
createScriptURL: Function; | ||
}; | ||
export declare const createPolicy: (name: string, options: PolicyOptions) => any; | ||
export declare const trusted: any; | ||
export { lwsInternalPolicy } from './lws-internal-policy'; | ||
export { trusted } from './trusted-policy'; | ||
export * from './types'; | ||
//# sourceMappingURL=index.d.ts.map |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
26692
19
393
4
2
+ Added@locker/shared@0.18.13
+ Added@locker/shared-dom@0.18.13
+ Added@locker/shared-url@0.18.13
+ Added@locker/html-sanitizer@0.18.13(transitive)
+ Added@locker/shared@0.18.13(transitive)
+ Added@locker/shared-dom@0.18.13(transitive)
+ Added@locker/shared-url@0.18.13(transitive)
+ Added@types/dompurify@2.3.4(transitive)
+ Added@types/trusted-types@2.0.7(transitive)
+ Addeddompurify@2.4.0(transitive)