Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/html/safestylesheet.js
2868 views
1
// Copyright 2014 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview The SafeStyleSheet type and its builders.
17
*
18
* TODO(xtof): Link to document stating type contract.
19
*/
20
21
goog.provide('goog.html.SafeStyleSheet');
22
23
goog.require('goog.array');
24
goog.require('goog.asserts');
25
goog.require('goog.string');
26
goog.require('goog.string.Const');
27
goog.require('goog.string.TypedString');
28
29
30
31
/**
32
* A string-like object which represents a CSS style sheet and that carries the
33
* security type contract that its value, as a string, will not cause untrusted
34
* script execution (XSS) when evaluated as CSS in a browser.
35
*
36
* Instances of this type must be created via the factory method
37
* {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its
38
* constructor. The constructor intentionally takes no parameters and the type
39
* is immutable; hence only a default instance corresponding to the empty string
40
* can be obtained via constructor invocation.
41
*
42
* A SafeStyleSheet's string representation can safely be interpolated as the
43
* content of a style element within HTML. The SafeStyleSheet string should
44
* not be escaped before interpolation.
45
*
46
* Values of this type must be composable, i.e. for any two values
47
* {@code styleSheet1} and {@code styleSheet2} of this type,
48
* {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) +
49
* goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that
50
* satisfies the SafeStyleSheet type constraint. This requirement implies that
51
* for any value {@code styleSheet} of this type,
52
* {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in
53
* "beginning of rule" context.
54
55
* A SafeStyleSheet can be constructed via security-reviewed unchecked
56
* conversions. In this case producers of SafeStyleSheet must ensure themselves
57
* that the SafeStyleSheet does not contain unsafe script. Note in particular
58
* that {@code <} is dangerous, even when inside CSS strings, and so should
59
* always be forbidden or CSS-escaped in user controlled input. For example, if
60
* {@code </style><script>evil</script>"} were interpolated
61
* inside a CSS string, it would break out of the context of the original
62
* style element and {@code evil} would execute. Also note that within an HTML
63
* style (raw text) element, HTML character references, such as
64
* {@code <}, are not allowed. See
65
*
66
http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements
67
* (similar considerations apply to the style element).
68
*
69
* @see goog.html.SafeStyleSheet#fromConstant
70
* @constructor
71
* @final
72
* @struct
73
* @implements {goog.string.TypedString}
74
*/
75
goog.html.SafeStyleSheet = function() {
76
/**
77
* The contained value of this SafeStyleSheet. The field has a purposely
78
* ugly name to make (non-compiled) code that attempts to directly access this
79
* field stand out.
80
* @private {string}
81
*/
82
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = '';
83
84
/**
85
* A type marker used to implement additional run-time type checking.
86
* @see goog.html.SafeStyleSheet#unwrap
87
* @const {!Object}
88
* @private
89
*/
90
this.SAFE_STYLE_SHEET_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
91
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
92
};
93
94
95
/**
96
* @override
97
* @const
98
*/
99
goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true;
100
101
102
/**
103
* Type marker for the SafeStyleSheet type, used to implement additional
104
* run-time type checking.
105
* @const {!Object}
106
* @private
107
*/
108
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
109
110
111
/**
112
* Creates a new SafeStyleSheet object by concatenating values.
113
* @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)}
114
* var_args Values to concatenate.
115
* @return {!goog.html.SafeStyleSheet}
116
*/
117
goog.html.SafeStyleSheet.concat = function(var_args) {
118
var result = '';
119
120
/**
121
* @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
122
* argument
123
*/
124
var addArgument = function(argument) {
125
if (goog.isArray(argument)) {
126
goog.array.forEach(argument, addArgument);
127
} else {
128
result += goog.html.SafeStyleSheet.unwrap(argument);
129
}
130
};
131
132
goog.array.forEach(arguments, addArgument);
133
return goog.html.SafeStyleSheet
134
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result);
135
};
136
137
138
/**
139
* Creates a SafeStyleSheet object from a compile-time constant string.
140
*
141
* {@code styleSheet} must not have any &lt; characters in it, so that
142
* the syntactic structure of the surrounding HTML is not affected.
143
*
144
* @param {!goog.string.Const} styleSheet A compile-time-constant string from
145
* which to create a SafeStyleSheet.
146
* @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to
147
* {@code styleSheet}.
148
*/
149
goog.html.SafeStyleSheet.fromConstant = function(styleSheet) {
150
var styleSheetString = goog.string.Const.unwrap(styleSheet);
151
if (styleSheetString.length === 0) {
152
return goog.html.SafeStyleSheet.EMPTY;
153
}
154
// > is a valid character in CSS selectors and there's no strict need to
155
// block it if we already block <.
156
goog.asserts.assert(
157
!goog.string.contains(styleSheetString, '<'),
158
"Forbidden '<' character in style sheet string: " + styleSheetString);
159
return goog.html.SafeStyleSheet
160
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString);
161
};
162
163
164
/**
165
* Returns this SafeStyleSheet's value as a string.
166
*
167
* IMPORTANT: In code where it is security relevant that an object's type is
168
* indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap}
169
* instead of this method. If in doubt, assume that it's security relevant. In
170
* particular, note that goog.html functions which return a goog.html type do
171
* not guarantee the returned instance is of the right type. For example:
172
*
173
* <pre>
174
* var fakeSafeHtml = new String('fake');
175
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
176
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
177
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
178
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
179
* // instanceof goog.html.SafeHtml.
180
* </pre>
181
*
182
* @see goog.html.SafeStyleSheet#unwrap
183
* @override
184
*/
185
goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() {
186
return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
187
};
188
189
190
if (goog.DEBUG) {
191
/**
192
* Returns a debug string-representation of this value.
193
*
194
* To obtain the actual string value wrapped in a SafeStyleSheet, use
195
* {@code goog.html.SafeStyleSheet.unwrap}.
196
*
197
* @see goog.html.SafeStyleSheet#unwrap
198
* @override
199
*/
200
goog.html.SafeStyleSheet.prototype.toString = function() {
201
return 'SafeStyleSheet{' +
202
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}';
203
};
204
}
205
206
207
/**
208
* Performs a runtime check that the provided object is indeed a
209
* SafeStyleSheet object, and returns its value.
210
*
211
* @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from.
212
* @return {string} The safeStyleSheet object's contained string, unless
213
* the run-time type check fails. In that case, {@code unwrap} returns an
214
* innocuous string, or, if assertions are enabled, throws
215
* {@code goog.asserts.AssertionError}.
216
*/
217
goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) {
218
// Perform additional Run-time type-checking to ensure that
219
// safeStyleSheet is indeed an instance of the expected type. This
220
// provides some additional protection against security bugs due to
221
// application code that disables type checks.
222
// Specifically, the following checks are performed:
223
// 1. The object is an instance of the expected type.
224
// 2. The object is not an instance of a subclass.
225
// 3. The object carries a type marker for the expected type. "Faking" an
226
// object requires a reference to the type marker, which has names intended
227
// to stand out in code reviews.
228
if (safeStyleSheet instanceof goog.html.SafeStyleSheet &&
229
safeStyleSheet.constructor === goog.html.SafeStyleSheet &&
230
safeStyleSheet
231
.SAFE_STYLE_SHEET_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
232
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
233
return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
234
} else {
235
goog.asserts.fail('expected object of type SafeStyleSheet, got \'' +
236
safeStyleSheet + '\' of type ' + goog.typeOf(safeStyleSheet));
237
return 'type_error:SafeStyleSheet';
238
}
239
};
240
241
242
/**
243
* Package-internal utility method to create SafeStyleSheet instances.
244
*
245
* @param {string} styleSheet The string to initialize the SafeStyleSheet
246
* object with.
247
* @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object.
248
* @package
249
*/
250
goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse =
251
function(styleSheet) {
252
return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_(
253
styleSheet);
254
};
255
256
257
/**
258
* Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This
259
* method exists only so that the compiler can dead code eliminate static
260
* fields (like EMPTY) when they're not accessed.
261
* @param {string} styleSheet
262
* @return {!goog.html.SafeStyleSheet}
263
* @private
264
*/
265
goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ =
266
function(styleSheet) {
267
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet;
268
return this;
269
};
270
271
272
/**
273
* A SafeStyleSheet instance corresponding to the empty string.
274
* @const {!goog.html.SafeStyleSheet}
275
*/
276
goog.html.SafeStyleSheet.EMPTY =
277
goog.html.SafeStyleSheet
278
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse('');
279
280