refactor(core): remove style sanitization code for [style]
/[style.prop]
bindings (#36965)
In 420b9be1c1
all style-based sanitization code was
disabled because modern browsers no longer allow for javascript expressions within
CSS. This patch is a follow-up patch which removes all traces of style sanitization
code (both instructions and runtime logic) for the `[style]` and `[style.prop]` bindings.
PR Close #36965
This commit is contained in:

committed by
Misko Hevery

parent
141fcb95a4
commit
45f4a47286
@ -227,7 +227,6 @@ export {
|
||||
ɵɵstylePropInterpolate7,
|
||||
ɵɵstylePropInterpolate8,
|
||||
ɵɵstylePropInterpolateV,
|
||||
ɵɵstyleSanitizer,
|
||||
ɵɵtemplate,
|
||||
ɵɵtemplateRefExtractor,
|
||||
ɵɵtext,
|
||||
@ -286,7 +285,6 @@ export {
|
||||
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
||||
} from './sanitization/bypass';
|
||||
export {
|
||||
ɵɵdefaultStyleSanitizer,
|
||||
ɵɵsanitizeHtml,
|
||||
ɵɵsanitizeResourceUrl,
|
||||
ɵɵsanitizeScript,
|
||||
|
@ -113,7 +113,6 @@ export {
|
||||
ɵɵstylePropInterpolate8,
|
||||
ɵɵstylePropInterpolateV,
|
||||
|
||||
ɵɵstyleSanitizer,
|
||||
ɵɵtemplate,
|
||||
|
||||
ɵɵtext,
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
import {bindingUpdated} from '../bindings';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
import {getLView, getSelectedIndex, getSelectedTNode, getTView, nextBindingIndex} from '../state';
|
||||
import {getLView, getSelectedTNode, getTView, nextBindingIndex} from '../state';
|
||||
import {elementAttributeInternal, storePropertyBindingMetadata} from './shared';
|
||||
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
*/
|
||||
|
||||
import {SafeValue, unwrapSafeValue} from '../../sanitization/bypass';
|
||||
import {stylePropNeedsSanitization, ɵɵsanitizeStyle} from '../../sanitization/sanitization';
|
||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||
import {KeyValueArray, keyValueArrayGet, keyValueArraySet} from '../../util/array_utils';
|
||||
import {assertDefined, assertEqual, assertLessThan, assertNotEqual, throwError} from '../../util/assert';
|
||||
import {EMPTY_ARRAY} from '../../util/empty';
|
||||
@ -18,11 +16,10 @@ import {bindingUpdated} from '../bindings';
|
||||
import {DirectiveDef} from '../interfaces/definition';
|
||||
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {RElement, Renderer3} from '../interfaces/renderer';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
|
||||
import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view';
|
||||
import {applyStyling} from '../node_manipulation';
|
||||
import {getCurrentDirectiveDef, getCurrentStyleSanitizer, getLView, getSelectedIndex, getTView, incrementBindingIndex, setCurrentStyleSanitizer} from '../state';
|
||||
import {getCurrentDirectiveDef, getLView, getSelectedIndex, getTView, incrementBindingIndex} from '../state';
|
||||
import {insertTStylingBinding} from '../styling/style_binding_list';
|
||||
import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
@ -31,26 +28,6 @@ import {getNativeByIndex} from '../util/view_utils';
|
||||
import {setDirectiveInputsWhichShadowsStyling} from './property';
|
||||
|
||||
|
||||
/**
|
||||
* Sets the current style sanitizer function which will then be used
|
||||
* within all follow-up prop and map-based style binding instructions
|
||||
* for the given element.
|
||||
*
|
||||
* Note that once styling has been applied to the element (i.e. once
|
||||
* `advance(n)` is executed or the hostBindings/template function exits)
|
||||
* then the active `sanitizerFn` will be set to `null`. This means that
|
||||
* once styling is applied to another element then a another call to
|
||||
* `styleSanitizer` will need to be made.
|
||||
*
|
||||
* @param sanitizerFn The sanitization function that will be used to
|
||||
* process style prop/value entries.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn|null): void {
|
||||
setCurrentStyleSanitizer(sanitizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a style binding on an element with the provided value.
|
||||
*
|
||||
@ -64,8 +41,6 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn|null): void {
|
||||
* @param prop A valid CSS property.
|
||||
* @param value New value to write (`null` or an empty string to remove).
|
||||
* @param suffix Optional suffix. Used with scalar values to add unit such as `px`.
|
||||
* Note that when a suffix is provided then the underlying sanitizer will
|
||||
* be ignored.
|
||||
*
|
||||
* Note that this will apply the provided style value to the host element if this function is called
|
||||
* within a host binding function.
|
||||
@ -183,11 +158,11 @@ export function classStringParser(keyValueArray: KeyValueArray<any>, text: strin
|
||||
*
|
||||
* @param prop property name.
|
||||
* @param value binding value.
|
||||
* @param suffixOrSanitizer suffix or sanitization function
|
||||
* @param suffix suffix for the property (e.g. `em` or `px`)
|
||||
* @param isClassBased `true` if `class` change (`false` if `style`)
|
||||
*/
|
||||
export function checkStylingProperty(
|
||||
prop: string, value: any|NO_CHANGE, suffixOrSanitizer: SanitizerFn|string|undefined|null,
|
||||
prop: string, value: any|NO_CHANGE, suffix: string|undefined|null,
|
||||
isClassBased: boolean): void {
|
||||
const lView = getLView();
|
||||
const tView = getTView();
|
||||
@ -199,19 +174,10 @@ export function checkStylingProperty(
|
||||
stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
|
||||
}
|
||||
if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
|
||||
// This is a work around. Once PR#34480 lands the sanitizer is passed explicitly and this line
|
||||
// can be removed.
|
||||
let styleSanitizer: StyleSanitizeFn|null;
|
||||
if (suffixOrSanitizer == null) {
|
||||
if (styleSanitizer = getCurrentStyleSanitizer()) {
|
||||
suffixOrSanitizer = styleSanitizer as any;
|
||||
}
|
||||
}
|
||||
const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
||||
updateStyling(
|
||||
tView, tNode, lView, lView[RENDERER], prop,
|
||||
lView[bindingIndex + 1] = normalizeAndApplySuffixOrSanitizer(value, suffixOrSanitizer),
|
||||
isClassBased, bindingIndex);
|
||||
lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,9 +185,7 @@ export function checkStylingProperty(
|
||||
* Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
|
||||
*
|
||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||
* function so that
|
||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
||||
* purposes.
|
||||
* function so that `style` can be processed. This is done for tree shaking purposes.
|
||||
* @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
|
||||
* have different parsers.)
|
||||
* @param value bound value from application
|
||||
@ -605,9 +569,8 @@ function collectStylingFromTAttrs(
|
||||
* keep additional `Map` to keep track of duplicates or items which have not yet been visited.
|
||||
*
|
||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||
* function so that
|
||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
||||
* purposes.
|
||||
* function so that `style` can be processed. This is done
|
||||
* for tree shaking purposes.
|
||||
* @param stringParser The parser is passed in so that it will be tree shakable. See
|
||||
* `styleStringParser` and `classStringParser`
|
||||
* @param value The value to parse/convert to `KeyValueArray`
|
||||
@ -639,19 +602,16 @@ export function toStylingKeyValueArray(
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a `value` for a `key` taking style sanitization into account.
|
||||
* Set a `value` for a `key`.
|
||||
*
|
||||
* See: `keyValueArraySet` for details
|
||||
*
|
||||
* @param keyValueArray KeyValueArray to add to.
|
||||
* @param key Style key to add. (This key will be checked if it needs sanitization)
|
||||
* @param value The value to set (If key needs sanitization it will be sanitized)
|
||||
* @param key Style key to add.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
export function styleKeyValueArraySet(keyValueArray: KeyValueArray<any>, key: string, value: any) {
|
||||
if (stylePropNeedsSanitization(key)) {
|
||||
value = ɵɵsanitizeStyle(value);
|
||||
}
|
||||
keyValueArraySet(keyValueArray, key, value);
|
||||
keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -784,10 +744,7 @@ function updateStyling(
|
||||
* NOTE: The styling stores two values.
|
||||
* 1. The raw value which came from the application is stored at `index + 0` location. (This value
|
||||
* is used for dirty checking).
|
||||
* 2. The normalized value (converted to `KeyValueArray` if map and sanitized) is stored at `index +
|
||||
* 1`.
|
||||
* The advantage of storing the sanitized value is that once the value is written we don't need
|
||||
* to worry about sanitizing it later or keeping track of the sanitizer.
|
||||
* 2. The normalized value is stored at `index + 1`.
|
||||
*
|
||||
* @param tData `TData` used for traversing the priority.
|
||||
* @param tNode `TNode` to use for resolving static styling. Also controls search direction.
|
||||
@ -867,22 +824,17 @@ function isStylingValuePresent(value: any): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes or adds suffix to the value.
|
||||
* Normalizes and/or adds a suffix to the value.
|
||||
*
|
||||
* If value is `null`/`undefined` no suffix is added
|
||||
* @param value
|
||||
* @param suffixOrSanitizer
|
||||
* @param suffix
|
||||
*/
|
||||
function normalizeAndApplySuffixOrSanitizer(
|
||||
value: any, suffixOrSanitizer: SanitizerFn|string|undefined|null): string|null|undefined|
|
||||
boolean {
|
||||
function normalizeSuffix(value: any, suffix: string|undefined|null): string|null|undefined|boolean {
|
||||
if (value == null /** || value === undefined */) {
|
||||
// do nothing
|
||||
} else if (typeof suffixOrSanitizer === 'function') {
|
||||
// sanitize the value.
|
||||
value = suffixOrSanitizer(value);
|
||||
} else if (typeof suffixOrSanitizer === 'string') {
|
||||
value = value + suffixOrSanitizer;
|
||||
} else if (typeof suffix === 'string') {
|
||||
value = value + suffix;
|
||||
} else if (typeof value === 'object') {
|
||||
value = stringify(unwrapSafeValue(value));
|
||||
}
|
||||
|
@ -133,7 +133,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||
'ɵɵstylePropInterpolate7': r3.ɵɵstylePropInterpolate7,
|
||||
'ɵɵstylePropInterpolate8': r3.ɵɵstylePropInterpolate8,
|
||||
'ɵɵstylePropInterpolateV': r3.ɵɵstylePropInterpolateV,
|
||||
'ɵɵstyleSanitizer': r3.ɵɵstyleSanitizer,
|
||||
'ɵɵclassProp': r3.ɵɵclassProp,
|
||||
'ɵɵselect': r3.ɵɵselect,
|
||||
'ɵɵadvance': r3.ɵɵadvance,
|
||||
@ -164,7 +163,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||
|
||||
'ɵɵsanitizeHtml': sanitization.ɵɵsanitizeHtml,
|
||||
'ɵɵsanitizeStyle': sanitization.ɵɵsanitizeStyle,
|
||||
'ɵɵdefaultStyleSanitizer': sanitization.ɵɵdefaultStyleSanitizer,
|
||||
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
||||
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
||||
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||
import {assertDefined, assertEqual} from '../util/assert';
|
||||
import {assertLViewOrUndefined} from './assert';
|
||||
import {DirectiveDef} from './interfaces/definition';
|
||||
@ -97,11 +96,6 @@ interface LFrame {
|
||||
*/
|
||||
currentNamespace: string|null;
|
||||
|
||||
/**
|
||||
* Current sanitizer
|
||||
*/
|
||||
currentSanitizer: StyleSanitizeFn|null;
|
||||
|
||||
|
||||
/**
|
||||
* The root index from which pure function instructions should calculate their binding
|
||||
@ -421,7 +415,6 @@ export function enterView(newView: LView, tNode: TNode|null): void {
|
||||
assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentSanitizer, null, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
|
||||
}
|
||||
@ -454,7 +447,6 @@ function createLFrame(parent: LFrame|null): LFrame {
|
||||
contextLView: null!, //
|
||||
elementDepthCount: 0, //
|
||||
currentNamespace: null, //
|
||||
currentSanitizer: null, //
|
||||
currentDirectiveIndex: -1, //
|
||||
bindingRootIndex: -1, //
|
||||
bindingIndex: -1, //
|
||||
@ -508,7 +500,6 @@ export function leaveView() {
|
||||
oldLFrame.elementDepthCount = 0;
|
||||
oldLFrame.currentDirectiveIndex = -1;
|
||||
oldLFrame.currentNamespace = null;
|
||||
oldLFrame.currentSanitizer = null;
|
||||
oldLFrame.bindingRootIndex = -1;
|
||||
oldLFrame.bindingIndex = -1;
|
||||
oldLFrame.currentQueryIndex = 0;
|
||||
@ -602,18 +593,3 @@ export function namespaceHTMLInternal() {
|
||||
export function getNamespace(): string|null {
|
||||
return instructionState.lFrame.currentNamespace;
|
||||
}
|
||||
|
||||
export function setCurrentStyleSanitizer(sanitizer: StyleSanitizeFn|null) {
|
||||
instructionState.lFrame.currentSanitizer = sanitizer;
|
||||
}
|
||||
|
||||
export function resetCurrentStyleSanitizer() {
|
||||
setCurrentStyleSanitizer(null);
|
||||
}
|
||||
|
||||
export function getCurrentStyleSanitizer() {
|
||||
// TODO(misko): This should throw when there is no LView, but it turns out we can get here from
|
||||
// `NodeStyleDebug` hence we return `null`. This should be fixed
|
||||
const lFrame = instructionState.lFrame;
|
||||
return lFrame === null ? null : lFrame.currentSanitizer;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import {allowSanitizationBypassAndThrow, BypassType, unwrapSafeValue} from './by
|
||||
import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer';
|
||||
import {Sanitizer} from './sanitizer';
|
||||
import {SecurityContext} from './security';
|
||||
import {StyleSanitizeFn, StyleSanitizeMode} from './style_sanitizer';
|
||||
import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer';
|
||||
|
||||
|
||||
@ -176,47 +175,6 @@ export function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl: any, tag: string, prop:
|
||||
return getUrlSanitizer(tag, prop)(unsafeUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default style sanitizer will handle sanitization for style properties.
|
||||
*
|
||||
* Style sanitization is no longer apart of Angular because modern browsers no
|
||||
* longer support javascript expressions. Therefore, the reason why this API
|
||||
* exists is exclusively for unwrapping any style value expressions that were
|
||||
* marked as `SafeValue` values.
|
||||
*
|
||||
* This API will be removed in a future release of Angular.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export const ɵɵdefaultStyleSanitizer =
|
||||
(function(prop: string, value: string|null, mode?: StyleSanitizeMode): string|boolean|null {
|
||||
if (value === undefined && mode === undefined) {
|
||||
// This is a workaround for the fact that `StyleSanitizeFn` should not exist once PR#34480
|
||||
// lands. For now the `StyleSanitizeFn` and should act like `(value: any) => string` as a
|
||||
// work around.
|
||||
return ɵɵsanitizeStyle(prop);
|
||||
}
|
||||
mode = mode || StyleSanitizeMode.ValidateAndSanitize;
|
||||
let doSanitizeValue = true;
|
||||
if (mode & StyleSanitizeMode.ValidateProperty) {
|
||||
doSanitizeValue = stylePropNeedsSanitization(prop);
|
||||
}
|
||||
|
||||
if (mode & StyleSanitizeMode.SanitizeOnly) {
|
||||
return doSanitizeValue ? ɵɵsanitizeStyle(value) : unwrapSafeValue(value);
|
||||
} else {
|
||||
return doSanitizeValue;
|
||||
}
|
||||
} as StyleSanitizeFn);
|
||||
|
||||
export function stylePropNeedsSanitization(prop: string): boolean {
|
||||
return prop === 'background-image' || prop === 'backgroundImage' || prop === 'background' ||
|
||||
prop === 'border-image' || prop === 'borderImage' || prop === 'border-image-source' ||
|
||||
prop === 'borderImageSource' || prop === 'filter' || prop === 'list-style' ||
|
||||
prop === 'listStyle' || prop === 'list-style-image' || prop === 'listStyleImage' ||
|
||||
prop === 'clip-path' || prop === 'clipPath';
|
||||
}
|
||||
|
||||
export function validateAgainstEventProperties(name: string) {
|
||||
if (name.toLowerCase().startsWith('on')) {
|
||||
const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
|
||||
|
@ -1,58 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {SafeValue} from './bypass';
|
||||
|
||||
/*
|
||||
* ========== WARNING ==========
|
||||
*
|
||||
* Style sanitization in Angular (for `[style.prop]` and `[style]` bindings)
|
||||
* is no longer required and has been removed. The reason why this feature
|
||||
* has been removed is because style-based sanitization is no longer
|
||||
* required with modern browsers.
|
||||
*
|
||||
* The contents of this file are still in flux. Various APIs and symbols will
|
||||
* be removed in a future version of Angular. Please hold off from modifying this
|
||||
* file for the time being.
|
||||
*
|
||||
* =============================
|
||||
*/
|
||||
|
||||
/**
|
||||
* A series of flags to instruct a style sanitizer to either validate
|
||||
* or sanitize a value.
|
||||
*
|
||||
* Because sanitization is dependent on the style property (i.e. style
|
||||
* sanitization for `width` is much different than for `background-image`)
|
||||
* the sanitization function (e.g. `StyleSanitizerFn`) needs to check a
|
||||
* property value first before it actually sanitizes any values.
|
||||
*
|
||||
* This enum exist to allow a style sanitization function to either only
|
||||
* do validation (check the property to see whether a value will be
|
||||
* sanitized or not) or to sanitize the value (or both).
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export const enum StyleSanitizeMode {
|
||||
/** Just check to see if the property is required to be sanitized or not */
|
||||
ValidateProperty = 0b01,
|
||||
/** Skip checking the property; just sanitize the value */
|
||||
SanitizeOnly = 0b10,
|
||||
/** Check the property and (if true) then sanitize the value */
|
||||
ValidateAndSanitize = 0b11,
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to intercept and sanitize style values before they are written to the renderer.
|
||||
*
|
||||
* This function is designed to be called in two modes. When a value is not provided
|
||||
* then the function will return a boolean whether a property will be sanitized later.
|
||||
* If a value is provided then the sanitized version of that will be returned.
|
||||
*/
|
||||
export interface StyleSanitizeFn {
|
||||
(prop: string, value: string|SafeValue|null, mode?: StyleSanitizeMode): any;
|
||||
}
|
Reference in New Issue
Block a user