fix(core): support prefix-insensitive DOM schema lookups and compile-… · angular/angular@daaf329 · GitHub
Skip to content

Commit daaf329

Browse files
alan-agius4alxhub
authored andcommitted
fix(core): support prefix-insensitive DOM schema lookups and compile-time i18n attribute validation (#68925)
Updates `DomElementSchemaRegistry` to strip `:svg:` and `:math:` namespace prefixes from tag names before querying `SECURITY_SCHEMA` at compile-time. This allows SVG and MathML attributes to correctly match their security contexts during compilation. PR Close #68925
1 parent 37e8aad commit daaf329

23 files changed

Lines changed: 476 additions & 503 deletions

File tree

‎goldens/public-api/core/index.api.md‎

Lines changed: 2 additions & 0 deletions
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"dist/main.js": 135813,
2+
"dist/main.js": 144843,
33
"dist/polyfills.js": 35883
44
}

‎packages/compiler/src/compiler.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import {publishFacade} from './jit_compiler_facade';
3232
import * as outputAst from './output/output_ast';
3333
import {global} from './util';
3434

35-
export {SECURITY_SCHEMA} from './schema/dom_security_schema';
3635
export {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from './core';
3736
export {core};
3837

‎packages/compiler/src/core.ts‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,6 @@ export interface Type extends Function {
7979
}
8080
export const Type = Function;
8181

82-
export enum SecurityContext {
83-
NONE = 0,
84-
HTML = 1,
85-
STYLE = 2,
86-
SCRIPT = 3,
87-
URL = 4,
88-
RESOURCE_URL = 5,
89-
ATTRIBUTE_NO_BINDING = 6,
90-
}
91-
9282
/**
9383
* Injection flags for DI.
9484
*/
@@ -331,3 +321,5 @@ export const enum AttributeMarker {
331321
*/
332322
I18n = 6,
333323
}
324+
325+
export {SecurityContext} from './schema/dom_security_schema';

‎packages/compiler/src/schema/dom_element_schema_registry.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,6 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
444444
propName = this.getMappedPropName(propName);
445445
}
446446

447-
// Make sure comparisons are case insensitive, so that case differences between attribute and
448-
// property names do not have a security impact.
449447
tagName = tagName.toLowerCase();
450448
propName = propName.toLowerCase();
451449

‎packages/compiler/src/schema/dom_security_schema.ts‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,24 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {SecurityContext} from '../core';
9+
/**
10+
* A SecurityContext marks a location that has dangerous security implications, e.g. a DOM property
11+
* like `innerHTML` that could cause Cross Site Scripting (XSS) security bugs when improperly
12+
* handled.
13+
*
14+
* See DomSanitizer for more details on security in Angular applications.
15+
*
16+
* @publicApi
17+
*/
18+
export enum SecurityContext {
19+
NONE = 0,
20+
HTML = 1,
21+
STYLE = 2,
22+
SCRIPT = 3,
23+
URL = 4,
24+
RESOURCE_URL = 5,
25+
ATTRIBUTE_NO_BINDING = 6,
26+
}
1027

1128
// =================================================================================================
1229
// =================================================================================================
@@ -18,11 +35,17 @@ import {SecurityContext} from '../core';
1835
//
1936
// =================================================================================================
2037

21-
/** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */
38+
/**
39+
* Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'.
40+
*/
2241
let _SECURITY_SCHEMA!: {[k: string]: SecurityContext};
2342
const SVG_NAMESPACE = 'svg';
2443
const MATH_ML_NAMESPACE = 'math';
2544

45+
/**
46+
* @remarks Keep is a copy of DOM Security Schema.
47+
* @see [SECURITY_SCHEMA](../../../compiler/src/schema/dom_security_schema.ts)
48+
*/
2649
export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
2750
if (!_SECURITY_SCHEMA) {
2851
_SECURITY_SCHEMA = {};

‎packages/compiler/src/template/pipeline/src/emit.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {resolveDeferDepsFns} from './phases/resolve_defer_deps_fns';
7272
import {resolveDollarEvent} from './phases/resolve_dollar_event';
7373
import {resolveI18nElementPlaceholders} from './phases/resolve_i18n_element_placeholders';
7474
import {resolveI18nExpressionPlaceholders} from './phases/resolve_i18n_expression_placeholders';
75+
import {resolveI18nAttrSanitizers} from './phases/resolve_i18n_attr_sanitizers';
7576
import {resolveNames} from './phases/resolve_names';
7677
import {resolveSanitizers} from './phases/resolve_sanitizers';
7778
import {saveAndRestoreView} from './phases/save_restore_view';
@@ -157,6 +158,7 @@ const phases: Phase[] = [
157158
{kind: Kind.Tmpl, fn: resolveI18nExpressionPlaceholders},
158159
{kind: Kind.Tmpl, fn: extractI18nMessages},
159160
{kind: Kind.Tmpl, fn: collectI18nConsts},
161+
{kind: Kind.Tmpl, fn: resolveI18nAttrSanitizers},
160162
{kind: Kind.Tmpl, fn: collectConstExpressions},
161163
{kind: Kind.Both, fn: collectElementConsts},
162164
{kind: Kind.Tmpl, fn: removeI18nContexts},

‎packages/compiler/src/template/pipeline/src/phases/const_collection.ts‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,7 @@ class ElementAttributes {
186186
if (value === null) {
187187
throw Error('Attribute, i18n attribute, & style element attributes must have a value');
188188
}
189-
if (trustedValueFn !== null) {
190-
if (!ir.isStringLiteral(value)) {
191-
throw Error('AssertionError: extracted attribute value should be string literal');
192-
}
189+
if (trustedValueFn !== null && ir.isStringLiteral(value)) {
193190
array.push(
194191
o.taggedTemplate(
195192
trustedValueFn,
Lines changed: 75 additions & 0 deletions

0 commit comments

Comments
 (0)