feat(ivy): bridge compile instructions to include sanitization helpers (#24938)

PR Close #24938
This commit is contained in:
Matias Niemelä
2018-07-11 10:58:18 -07:00
committed by Victor Berchet
parent 13f3157823
commit 169e9dd2c8
21 changed files with 963 additions and 490 deletions

View File

@ -0,0 +1,143 @@
/**
* @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
*/
const BRAND = '__SANITIZER_TRUSTED_BRAND__';
export const enum BypassType {
Url = 'Url',
Html = 'Html',
ResourceUrl = 'ResourceUrl',
Script = 'Script',
Style = 'Style',
}
/**
* A branded trusted string used with sanitization.
*
* See: {@link TrustedHtmlString}, {@link TrustedResourceUrlString}, {@link TrustedScriptString},
* {@link TrustedStyleString}, {@link TrustedUrlString}
*/
export interface TrustedString extends String { [BRAND]: BypassType; }
/**
* A branded trusted string used with sanitization of `html` strings.
*
* See: {@link bypassSanitizationTrustHtml} and {@link htmlSanitizer}.
*/
export interface TrustedHtmlString extends TrustedString { [BRAND]: BypassType.Html; }
/**
* A branded trusted string used with sanitization of `style` strings.
*
* See: {@link bypassSanitizationTrustStyle} and {@link styleSanitizer}.
*/
export interface TrustedStyleString extends TrustedString { [BRAND]: BypassType.Style; }
/**
* A branded trusted string used with sanitization of `url` strings.
*
* See: {@link bypassSanitizationTrustScript} and {@link scriptSanitizer}.
*/
export interface TrustedScriptString extends TrustedString { [BRAND]: BypassType.Script; }
/**
* A branded trusted string used with sanitization of `url` strings.
*
* See: {@link bypassSanitizationTrustUrl} and {@link urlSanitizer}.
*/
export interface TrustedUrlString extends TrustedString { [BRAND]: BypassType.Url; }
/**
* A branded trusted string used with sanitization of `resourceUrl` strings.
*
* See: {@link bypassSanitizationTrustResourceUrl} and {@link resourceUrlSanitizer}.
*/
export interface TrustedResourceUrlString extends TrustedString { [BRAND]: BypassType.ResourceUrl; }
export function allowSanitizationBypass(value: any, type: BypassType): boolean {
return (value instanceof String && (value as TrustedStyleString)[BRAND] === type) ? true : false;
}
/**
* Mark `html` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link htmlSanitizer} to be trusted implicitly.
*
* @param trustedHtml `html` string which needs to be implicitly trusted.
* @returns a `html` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustHtml(trustedHtml: string): TrustedHtmlString {
return bypassSanitizationTrustString(trustedHtml, BypassType.Html);
}
/**
* Mark `style` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link styleSanitizer} to be trusted implicitly.
*
* @param trustedStyle `style` string which needs to be implicitly trusted.
* @returns a `style` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustStyle(trustedStyle: string): TrustedStyleString {
return bypassSanitizationTrustString(trustedStyle, BypassType.Style);
}
/**
* Mark `script` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link scriptSanitizer} to be trusted implicitly.
*
* @param trustedScript `script` string which needs to be implicitly trusted.
* @returns a `script` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustScript(trustedScript: string): TrustedScriptString {
return bypassSanitizationTrustString(trustedScript, BypassType.Script);
}
/**
* Mark `url` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link urlSanitizer} to be trusted implicitly.
*
* @param trustedUrl `url` string which needs to be implicitly trusted.
* @returns a `url` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustUrl(trustedUrl: string): TrustedUrlString {
return bypassSanitizationTrustString(trustedUrl, BypassType.Url);
}
/**
* Mark `url` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
*
* @param trustedResourceUrl `url` string which needs to be implicitly trusted.
* @returns a `url` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustResourceUrl(trustedResourceUrl: string):
TrustedResourceUrlString {
return bypassSanitizationTrustString(trustedResourceUrl, BypassType.ResourceUrl);
}
function bypassSanitizationTrustString(
trustedString: string, mode: BypassType.Html): TrustedHtmlString;
function bypassSanitizationTrustString(
trustedString: string, mode: BypassType.Style): TrustedStyleString;
function bypassSanitizationTrustString(
trustedString: string, mode: BypassType.Script): TrustedScriptString;
function bypassSanitizationTrustString(
trustedString: string, mode: BypassType.Url): TrustedUrlString;
function bypassSanitizationTrustString(
trustedString: string, mode: BypassType.ResourceUrl): TrustedResourceUrlString;
function bypassSanitizationTrustString(trustedString: string, mode: BypassType): TrustedString {
const trusted = new String(trustedString) as TrustedString;
trusted[BRAND] = mode;
return trusted;
}

View File

@ -9,63 +9,13 @@
import {getCurrentSanitizer} from '../render3/instructions';
import {stringify} from '../render3/util';
import {BypassType, allowSanitizationBypass} from './bypass';
import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer';
import {SecurityContext} from './security';
import {_sanitizeStyle as _sanitizeStyle} from './style_sanitizer';
import {StyleSanitizeFn, _sanitizeStyle as _sanitizeStyle} from './style_sanitizer';
import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer';
const BRAND = '__SANITIZER_TRUSTED_BRAND__';
/**
* A branded trusted string used with sanitization.
*
* See: {@link TrustedHtmlString}, {@link TrustedResourceUrlString}, {@link TrustedScriptString},
* {@link TrustedStyleString}, {@link TrustedUrlString}
*/
export interface TrustedString extends String {
'__SANITIZER_TRUSTED_BRAND__': 'Html'|'Style'|'Script'|'Url'|'ResourceUrl';
}
/**
* A branded trusted string used with sanitization of `html` strings.
*
* See: {@link bypassSanitizationTrustHtml} and {@link htmlSanitizer}.
*/
export interface TrustedHtmlString extends TrustedString { '__SANITIZER_TRUSTED_BRAND__': 'Html'; }
/**
* A branded trusted string used with sanitization of `style` strings.
*
* See: {@link bypassSanitizationTrustStyle} and {@link styleSanitizer}.
*/
export interface TrustedStyleString extends TrustedString {
'__SANITIZER_TRUSTED_BRAND__': 'Style';
}
/**
* A branded trusted string used with sanitization of `url` strings.
*
* See: {@link bypassSanitizationTrustScript} and {@link scriptSanitizer}.
*/
export interface TrustedScriptString extends TrustedString {
'__SANITIZER_TRUSTED_BRAND__': 'Script';
}
/**
* A branded trusted string used with sanitization of `url` strings.
*
* See: {@link bypassSanitizationTrustUrl} and {@link urlSanitizer}.
*/
export interface TrustedUrlString extends TrustedString { '__SANITIZER_TRUSTED_BRAND__': 'Url'; }
/**
* A branded trusted string used with sanitization of `resourceUrl` strings.
*
* See: {@link bypassSanitizationTrustResourceUrl} and {@link resourceUrlSanitizer}.
*/
export interface TrustedResourceUrlString extends TrustedString {
'__SANITIZER_TRUSTED_BRAND__': 'ResourceUrl';
}
/**
* An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing
@ -85,7 +35,7 @@ export function sanitizeHtml(unsafeHtml: any): string {
if (s) {
return s.sanitize(SecurityContext.HTML, unsafeHtml) || '';
}
if (unsafeHtml instanceof String && (unsafeHtml as TrustedHtmlString)[BRAND] === 'Html') {
if (allowSanitizationBypass(unsafeHtml, BypassType.Html)) {
return unsafeHtml.toString();
}
return _sanitizeHtml(document, stringify(unsafeHtml));
@ -109,7 +59,7 @@ export function sanitizeStyle(unsafeStyle: any): string {
if (s) {
return s.sanitize(SecurityContext.STYLE, unsafeStyle) || '';
}
if (unsafeStyle instanceof String && (unsafeStyle as TrustedStyleString)[BRAND] === 'Style') {
if (allowSanitizationBypass(unsafeStyle, BypassType.Style)) {
return unsafeStyle.toString();
}
return _sanitizeStyle(stringify(unsafeStyle));
@ -134,7 +84,7 @@ export function sanitizeUrl(unsafeUrl: any): string {
if (s) {
return s.sanitize(SecurityContext.URL, unsafeUrl) || '';
}
if (unsafeUrl instanceof String && (unsafeUrl as TrustedUrlString)[BRAND] === 'Url') {
if (allowSanitizationBypass(unsafeUrl, BypassType.Url)) {
return unsafeUrl.toString();
}
return _sanitizeUrl(stringify(unsafeUrl));
@ -154,8 +104,7 @@ export function sanitizeResourceUrl(unsafeResourceUrl: any): string {
if (s) {
return s.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || '';
}
if (unsafeResourceUrl instanceof String &&
(unsafeResourceUrl as TrustedResourceUrlString)[BRAND] === 'ResourceUrl') {
if (allowSanitizationBypass(unsafeResourceUrl, BypassType.ResourceUrl)) {
return unsafeResourceUrl.toString();
}
throw new Error('unsafe value used in a resource URL context (see http://g.co/ng/security#xss)');
@ -175,85 +124,22 @@ export function sanitizeScript(unsafeScript: any): string {
if (s) {
return s.sanitize(SecurityContext.SCRIPT, unsafeScript) || '';
}
if (unsafeScript instanceof String && (unsafeScript as TrustedScriptString)[BRAND] === 'Script') {
if (allowSanitizationBypass(unsafeScript, BypassType.Script)) {
return unsafeScript.toString();
}
throw new Error('unsafe value used in a script context');
}
/**
* Mark `html` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link htmlSanitizer} to be trusted implicitly.
*
* @param trustedHtml `html` string which needs to be implicitly trusted.
* @returns a `html` `String` which has been branded to be implicitly trusted.
* The default style sanitizer will handle sanitization for style properties by
* sanitizing any CSS property that can include a `url` value (usually image-based properties)
*/
export function bypassSanitizationTrustHtml(trustedHtml: string): TrustedHtmlString {
return bypassSanitizationTrustString(trustedHtml, 'Html');
}
/**
* Mark `style` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link styleSanitizer} to be trusted implicitly.
*
* @param trustedStyle `style` string which needs to be implicitly trusted.
* @returns a `style` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustStyle(trustedStyle: string): TrustedStyleString {
return bypassSanitizationTrustString(trustedStyle, 'Style');
}
/**
* Mark `script` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link scriptSanitizer} to be trusted implicitly.
*
* @param trustedScript `script` string which needs to be implicitly trusted.
* @returns a `script` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustScript(trustedScript: string): TrustedScriptString {
return bypassSanitizationTrustString(trustedScript, 'Script');
}
/**
* Mark `url` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link urlSanitizer} to be trusted implicitly.
*
* @param trustedUrl `url` string which needs to be implicitly trusted.
* @returns a `url` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustUrl(trustedUrl: string): TrustedUrlString {
return bypassSanitizationTrustString(trustedUrl, 'Url');
}
/**
* Mark `url` string as trusted.
*
* This function wraps the trusted string in `String` and brands it in a way which makes it
* recognizable to {@link resourceUrlSanitizer} to be trusted implicitly.
*
* @param trustedResourceUrl `url` string which needs to be implicitly trusted.
* @returns a `url` `String` which has been branded to be implicitly trusted.
*/
export function bypassSanitizationTrustResourceUrl(trustedResourceUrl: string):
TrustedResourceUrlString {
return bypassSanitizationTrustString(trustedResourceUrl, 'ResourceUrl');
}
export const defaultStyleSanitizer = (function(prop: string, value?: string): string | boolean {
if (value === undefined) {
return prop === 'background-image' || prop === 'background' || prop === 'border-image' ||
prop === 'filter' || prop === 'filter' || prop === 'list-style' ||
prop === 'list-style-image';
}
function bypassSanitizationTrustString(trustedString: string, mode: 'Html'): TrustedHtmlString;
function bypassSanitizationTrustString(trustedString: string, mode: 'Style'): TrustedStyleString;
function bypassSanitizationTrustString(trustedString: string, mode: 'Script'): TrustedScriptString;
function bypassSanitizationTrustString(trustedString: string, mode: 'Url'): TrustedUrlString;
function bypassSanitizationTrustString(
trustedString: string, mode: 'ResourceUrl'): TrustedResourceUrlString;
function bypassSanitizationTrustString(
trustedString: string,
mode: 'Html' | 'Style' | 'Script' | 'Url' | 'ResourceUrl'): TrustedString {
const trusted = new String(trustedString) as TrustedString;
trusted[BRAND] = mode;
return trusted;
}
return sanitizeStyle(value);
} as StyleSanitizeFn);

View File

@ -101,3 +101,19 @@ export function _sanitizeStyle(value: string): string {
return 'unsafe';
}
/**
* 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 {
/** This mode is designed to instruct whether the property will be used for sanitization
* at a later point */
(prop: string): boolean;
/** This mode is designed to sanitize the provided value */
(prop: string, value: string): string;
}