diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 8483fda6493..91c47f6a2fa 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -16,6 +16,7 @@ export {convertToBitFlags as ɵconvertToBitFlags, setCurrentInjector as ɵsetCur export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDeclaration, ɵɵInjectorDef} from './di/interface/defs'; export {InternalEnvironmentProviders as ɵInternalEnvironmentProviders, isEnvironmentProviders as ɵisEnvironmentProviders} from './di/interface/provider'; export {INJECTOR_SCOPE as ɵINJECTOR_SCOPE} from './di/scope'; +export {XSS_SECURITY_URL as ɵXSS_SECURITY_URL} from './error_details_base_url'; export {formatRuntimeError as ɵformatRuntimeError, RuntimeError as ɵRuntimeError} from './errors'; export {CurrencyIndex as ɵCurrencyIndex, ExtraLocaleDataIndex as ɵExtraLocaleDataIndex, findLocaleData as ɵfindLocaleData, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, LocaleDataIndex as ɵLocaleDataIndex, registerLocaleData as ɵregisterLocaleData, unregisterAllLocaleData as ɵunregisterLocaleData} from './i18n/locale_data_api'; export {DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID} from './i18n/localization'; diff --git a/packages/core/src/error_details_base_url.ts b/packages/core/src/error_details_base_url.ts index 2c7cac3c6f1..417f681e355 100644 --- a/packages/core/src/error_details_base_url.ts +++ b/packages/core/src/error_details_base_url.ts @@ -9,8 +9,13 @@ /** * Base URL for the error details page. * - * Keep the files below in full sync: + * Keep this constant in sync across: * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts * - packages/core/src/error_details_base_url.ts */ export const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors'; + +/** + * URL for the XSS security documentation. + */ +export const XSS_SECURITY_URL = 'https://g.co/ng/security#xss'; diff --git a/packages/core/src/render3/i18n/i18n_parse.ts b/packages/core/src/render3/i18n/i18n_parse.ts index 2ec4dcdc3ff..854408c1e0a 100644 --- a/packages/core/src/render3/i18n/i18n_parse.ts +++ b/packages/core/src/render3/i18n/i18n_parse.ts @@ -8,6 +8,7 @@ import '../../util/ng_dev_mode'; import '../../util/ng_i18n_closure_mode'; +import {XSS_SECURITY_URL} from '../../error_details_base_url'; import {getTemplateContent, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS} from '../../sanitization/html_sanitizer'; import {getInertBodyHelper} from '../../sanitization/inert_body'; import {_sanitizeUrl} from '../../sanitization/url_sanitizer'; @@ -632,7 +633,7 @@ function walkIcuTree( console.warn( `WARNING: ignoring unsafe attribute value ` + `${lowerAttrName} on element ${tagName} ` + - `(see https://g.co/ng/security#xss)`); + `(see ${XSS_SECURITY_URL})`); } } else { addCreateAttribute(create, newIndex, attr); diff --git a/packages/core/src/sanitization/bypass.ts b/packages/core/src/sanitization/bypass.ts index 05364c268f4..e2209bb09ea 100644 --- a/packages/core/src/sanitization/bypass.ts +++ b/packages/core/src/sanitization/bypass.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {XSS_SECURITY_URL} from '../error_details_base_url'; export const enum BypassType { Url = 'URL', @@ -65,7 +66,7 @@ abstract class SafeValueImpl implements SafeValue { toString() { return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` + - ` (see https://g.co/ng/security#xss)`; + ` (see ${XSS_SECURITY_URL})`; } } @@ -118,8 +119,7 @@ export function allowSanitizationBypassAndThrow(value: any, type: BypassType): b if (actualType != null && actualType !== type) { // Allow ResourceURLs in URL contexts, they are strictly more trusted. if (actualType === BypassType.ResourceUrl && type === BypassType.Url) return true; - throw new Error( - `Required a safe ${type}, got a ${actualType} (see https://g.co/ng/security#xss)`); + throw new Error(`Required a safe ${type}, got a ${actualType} (see ${XSS_SECURITY_URL})`); } return actualType === type; } diff --git a/packages/core/src/sanitization/html_sanitizer.ts b/packages/core/src/sanitization/html_sanitizer.ts index f3cdc8bbb39..cf776e6b16a 100644 --- a/packages/core/src/sanitization/html_sanitizer.ts +++ b/packages/core/src/sanitization/html_sanitizer.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {XSS_SECURITY_URL} from '../error_details_base_url'; import {TrustedHTML} from '../util/security/trusted_type_defs'; import {trustedHTMLFromString} from '../util/security/trusted_types'; @@ -268,8 +269,7 @@ export function _sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): Trusted const safeHtml = sanitizer.sanitizeChildren( getTemplateContent(inertBodyElement!) as Element || inertBodyElement); if ((typeof ngDevMode === 'undefined' || ngDevMode) && sanitizer.sanitizedSomething) { - console.warn( - 'WARNING: sanitizing HTML stripped some content, see https://g.co/ng/security#xss'); + console.warn(`WARNING: sanitizing HTML stripped some content, see ${XSS_SECURITY_URL}`); } return trustedHTMLFromString(safeHtml); diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index 5d5a234964c..631101d6fe4 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {XSS_SECURITY_URL} from '../error_details_base_url'; import {RuntimeError, RuntimeErrorCode} from '../errors'; import {getDocument} from '../render3/interfaces/document'; import {SANITIZER} from '../render3/interfaces/view'; @@ -120,8 +121,7 @@ export function ɵɵsanitizeResourceUrl(unsafeResourceUrl: any): TrustedScriptUR } throw new RuntimeError( RuntimeErrorCode.UNSAFE_VALUE_IN_RESOURCE_URL, - ngDevMode && - 'unsafe value used in a resource URL context (see https://g.co/ng/security#xss)'); + ngDevMode && `unsafe value used in a resource URL context (see ${XSS_SECURITY_URL})`); } /** diff --git a/packages/core/src/sanitization/url_sanitizer.ts b/packages/core/src/sanitization/url_sanitizer.ts index b2966b472a6..f90528529d3 100644 --- a/packages/core/src/sanitization/url_sanitizer.ts +++ b/packages/core/src/sanitization/url_sanitizer.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {XSS_SECURITY_URL} from '../error_details_base_url'; /** * A pattern that recognizes a commonly useful subset of URLs that are safe. @@ -40,7 +41,7 @@ export function _sanitizeUrl(url: string): string { if (url.match(SAFE_URL_PATTERN)) return url; if (typeof ngDevMode === 'undefined' || ngDevMode) { - console.warn(`WARNING: sanitizing unsafe URL value ${url} (see https://g.co/ng/security#xss)`); + console.warn(`WARNING: sanitizing unsafe URL value ${url} (see ${XSS_SECURITY_URL})`); } return 'unsafe:' + url; diff --git a/packages/core/test/sanitization/sanitization_spec.ts b/packages/core/test/sanitization/sanitization_spec.ts index 3566f85ff4c..ebab2e4287c 100644 --- a/packages/core/test/sanitization/sanitization_spec.ts +++ b/packages/core/test/sanitization/sanitization_spec.ts @@ -52,8 +52,7 @@ describe('sanitization', () => { }); it('should sanitize resourceUrl', () => { - const ERROR = - 'NG0904: unsafe value used in a resource URL context (see https://g.co/ng/security#xss)'; + const ERROR = /NG0904: unsafe value used in a resource URL context.*/; expect(() => ɵɵsanitizeResourceUrl('http://server')).toThrowError(ERROR); expect(() => ɵɵsanitizeResourceUrl('javascript:true')).toThrowError(ERROR); expect(() => ɵɵsanitizeResourceUrl(bypassSanitizationTrustHtml('javascript:true'))) @@ -106,8 +105,7 @@ describe('sanitization', () => { }); it('should sanitize resourceUrls via sanitizeUrlOrResourceUrl', () => { - const ERROR = - 'NG0904: unsafe value used in a resource URL context (see https://g.co/ng/security#xss)'; + const ERROR = /NG0904: unsafe value used in a resource URL context.*/; expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'iframe', 'src')).toThrowError(ERROR); expect(() => ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'iframe', 'src')) .toThrowError(ERROR); diff --git a/packages/platform-browser/src/security/dom_sanitization_service.ts b/packages/platform-browser/src/security/dom_sanitization_service.ts index c9669504c12..b25ffd5ef50 100644 --- a/packages/platform-browser/src/security/dom_sanitization_service.ts +++ b/packages/platform-browser/src/security/dom_sanitization_service.ts @@ -7,7 +7,7 @@ */ import {DOCUMENT} from '@angular/common'; -import {forwardRef, Inject, Injectable, Injector, Sanitizer, SecurityContext, ɵ_sanitizeHtml as _sanitizeHtml, ɵ_sanitizeUrl as _sanitizeUrl, ɵallowSanitizationBypassAndThrow as allowSanitizationBypassOrThrow, ɵbypassSanitizationTrustHtml as bypassSanitizationTrustHtml, ɵbypassSanitizationTrustResourceUrl as bypassSanitizationTrustResourceUrl, ɵbypassSanitizationTrustScript as bypassSanitizationTrustScript, ɵbypassSanitizationTrustStyle as bypassSanitizationTrustStyle, ɵbypassSanitizationTrustUrl as bypassSanitizationTrustUrl, ɵBypassType as BypassType, ɵgetSanitizationBypassType as getSanitizationBypassType, ɵunwrapSafeValue as unwrapSafeValue} from '@angular/core'; +import {forwardRef, Inject, Injectable, Injector, Sanitizer, SecurityContext, ɵ_sanitizeHtml as _sanitizeHtml, ɵ_sanitizeUrl as _sanitizeUrl, ɵallowSanitizationBypassAndThrow as allowSanitizationBypassOrThrow, ɵbypassSanitizationTrustHtml as bypassSanitizationTrustHtml, ɵbypassSanitizationTrustResourceUrl as bypassSanitizationTrustResourceUrl, ɵbypassSanitizationTrustScript as bypassSanitizationTrustScript, ɵbypassSanitizationTrustStyle as bypassSanitizationTrustStyle, ɵbypassSanitizationTrustUrl as bypassSanitizationTrustUrl, ɵBypassType as BypassType, ɵgetSanitizationBypassType as getSanitizationBypassType, ɵunwrapSafeValue as unwrapSafeValue, ɵXSS_SECURITY_URL as XSS_SECURITY_URL} from '@angular/core'; export {SecurityContext}; @@ -182,10 +182,9 @@ export class DomSanitizerImpl extends DomSanitizer { if (allowSanitizationBypassOrThrow(value, BypassType.ResourceUrl)) { return unwrapSafeValue(value); } - throw new Error( - 'unsafe value used in a resource URL context (see https://g.co/ng/security#xss)'); + throw new Error(`unsafe value used in a resource URL context (see ${XSS_SECURITY_URL})`); default: - throw new Error(`Unexpected SecurityContext ${ctx} (see https://g.co/ng/security#xss)`); + throw new Error(`Unexpected SecurityContext ${ctx} (see ${XSS_SECURITY_URL})`); } }