diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 3ea863e09d..87e108d8e4 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -320,4 +320,9 @@ export class Identifiers { static sanitizeUrl: o.ExternalReference = {name: 'ɵɵsanitizeUrl', moduleName: CORE}; static sanitizeUrlOrResourceUrl: o.ExternalReference = {name: 'ɵɵsanitizeUrlOrResourceUrl', moduleName: CORE}; + static trustConstantHtml: o.ExternalReference = {name: 'ɵɵtrustConstantHtml', moduleName: CORE}; + static trustConstantScript: + o.ExternalReference = {name: 'ɵɵtrustConstantScript', moduleName: CORE}; + static trustConstantResourceUrl: + o.ExternalReference = {name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE}; } diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index eb92a1590c..e71b84c05d 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -568,7 +568,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const nonContentSelectAttributes = ngContent.attributes.filter(attr => attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR); - const attributes = this.getAttributeExpressions(nonContentSelectAttributes, [], []); + const attributes = + this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []); if (attributes.length > 0) { parameters.push(o.literal(projectionSlotIdx), o.literalArr(attributes)); @@ -635,7 +636,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // add attributes for directive and projection matching purposes const attributes: o.Expression[] = this.getAttributeExpressions( - outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], i18nAttrs); + element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], i18nAttrs); parameters.push(this.addAttrsToConsts(attributes)); // local refs (ex.:
) @@ -867,8 +868,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // prepare attributes parameter (including attributes used for directive matching) const [i18nStaticAttrs, staticAttrs] = partitionArray(template.attributes, hasI18nMeta); const attrsExprs: o.Expression[] = this.getAttributeExpressions( - staticAttrs, template.inputs, template.outputs, undefined /* styles */, - template.templateAttrs, i18nStaticAttrs); + NG_TEMPLATE_TAG_NAME, staticAttrs, template.inputs, template.outputs, + undefined /* styles */, template.templateAttrs, i18nStaticAttrs); parameters.push(this.addAttrsToConsts(attrsExprs)); // local refs (ex.: ) @@ -1285,8 +1286,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver * because those values are intended to always be generated as property instructions. */ private getAttributeExpressions( - renderAttributes: t.TextAttribute[], inputs: t.BoundAttribute[], outputs: t.BoundEvent[], - styles?: StylingBuilder, templateAttrs: (t.BoundAttribute|t.TextAttribute)[] = [], + elementName: string, renderAttributes: t.TextAttribute[], inputs: t.BoundAttribute[], + outputs: t.BoundEvent[], styles?: StylingBuilder, + templateAttrs: (t.BoundAttribute|t.TextAttribute)[] = [], i18nAttrs: (t.BoundAttribute|t.TextAttribute)[] = []): o.Expression[] { const alreadySeen = new Set(); const attrExprs: o.Expression[] = []; @@ -1296,7 +1298,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver if (attr.name === NG_PROJECT_AS_ATTR_NAME) { ngProjectAsAttr = attr; } - attrExprs.push(...getAttributeNameLiterals(attr.name), asLiteral(attr.value)); + attrExprs.push( + ...getAttributeNameLiterals(attr.name), trustedConstAttribute(elementName, attr)); }); // Keep ngProjectAs next to the other name, value pairs so we can verify that we match @@ -2128,6 +2131,20 @@ export function resolveSanitizationFn(context: core.SecurityContext, isAttribute } } +function trustedConstAttribute(tagName: string, attr: t.TextAttribute): o.Expression { + const value = asLiteral(attr.value); + switch (elementRegistry.securityContext(tagName, attr.name, /* isAttribute */ true)) { + case core.SecurityContext.HTML: + return o.importExpr(R3.trustConstantHtml).callFn([value], attr.valueSpan); + case core.SecurityContext.SCRIPT: + return o.importExpr(R3.trustConstantScript).callFn([value], attr.valueSpan); + case core.SecurityContext.RESOURCE_URL: + return o.importExpr(R3.trustConstantResourceUrl).callFn([value], attr.valueSpan); + default: + return value; + } +} + function isSingleElementTemplate(children: t.Node[]): children is[t.Element] { return children.length === 1 && children[0] instanceof t.Element; } diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 91a0d77b0e..07ccc60cf2 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -290,6 +290,9 @@ export { ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, + ɵɵtrustConstantHtml, + ɵɵtrustConstantResourceUrl, + ɵɵtrustConstantScript, } from './sanitization/sanitization'; export { noSideEffects as ɵnoSideEffects, diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 894fe7711a..9f028b1d43 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -166,4 +166,7 @@ export const angularCoreEnv: {[name: string]: Function} = 'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript, 'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl, 'ɵɵsanitizeUrlOrResourceUrl': sanitization.ɵɵsanitizeUrlOrResourceUrl, + 'ɵɵtrustConstantHtml': sanitization.ɵɵtrustConstantHtml, + 'ɵɵtrustConstantScript': sanitization.ɵɵtrustConstantScript, + 'ɵɵtrustConstantResourceUrl': sanitization.ɵɵtrustConstantResourceUrl, }))(); diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index b32c1e1c3e..49b151a1e0 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -10,6 +10,8 @@ import {getDocument} from '../render3/interfaces/document'; import {SANITIZER} from '../render3/interfaces/view'; import {getLView} from '../render3/state'; import {renderStringify} from '../render3/util/misc_utils'; +import {TrustedHTML, TrustedScript, TrustedScriptURL} from '../util/security/trusted_type_defs'; +import {trustedHTMLFromString, trustedScriptFromString, trustedScriptURLFromString} from '../util/security/trusted_types'; import {allowSanitizationBypassAndThrow, BypassType, unwrapSafeValue} from './bypass'; import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer'; @@ -139,6 +141,51 @@ export function ɵɵsanitizeScript(unsafeScript: any): string { throw new Error('unsafe value used in a script context'); } +/** + * Promotes the given constant string to a TrustedHTML. + * @param html constant string containing trusted HTML. + * @returns TrustedHTML wrapping `html`. + * + * @security This is a security-sensitive function and should only be used to + * convert constant values of attributes and properties found in + * application-provided Angular templates to TrustedHTML. + * + * @codeGenApi + */ +export function ɵɵtrustConstantHtml(html: string): TrustedHTML|string { + return trustedHTMLFromString(html); +} + +/** + * Promotes the given constant string to a TrustedScript. + * @param script constant string containing a trusted script. + * @returns TrustedScript wrapping `script`. + * + * @security This is a security-sensitive function and should only be used to + * convert constant values of attributes and properties found in + * application-provided Angular templates to TrustedScript. + * + * @codeGenApi + */ +export function ɵɵtrustConstantScript(script: string): TrustedScript|string { + return trustedScriptFromString(script); +} + +/** + * Promotes the given constant string to a TrustedScriptURL. + * @param url constant string containing a trusted script URL. + * @returns TrustedScriptURL wrapping `url`. + * + * @security This is a security-sensitive function and should only be used to + * convert constant values of attributes and properties found in + * application-provided Angular templates to TrustedScriptURL. + * + * @codeGenApi + */ +export function ɵɵtrustConstantResourceUrl(url: string): TrustedScriptURL|string { + return trustedScriptURLFromString(url); +} + /** * Detects which sanitizer to use for URL property, based on tag name and prop name. *