12
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
// See the License for the specific language governing permissions and
14
14
// limitations under the License.
15
- // SPDX-License-Identifier: MIT
15
+ // SPDX-License-Identifier: Apache-2.0
16
16
17
17
// Based upon:
18
18
// https://github.com/google/caja/blob/master/src/com/google/caja/ses/startSES.js
19
19
// https://github.com/google/caja/blob/master/src/com/google/caja/ses/repairES5.js
20
- // https://github.com/tc39/proposal-frozen-realms /blob/91ac390e3451da92b5c27e354b39e52b7636a437 /shim/src/deep- freeze.js
20
+ // https://github.com/tc39/proposal-ses /blob/e5271cc42a257a05dcae2fd94713ed2f46c08620 /shim/src/freeze.js
21
21
22
- /* global WebAssembly, SharedArrayBuffer */
22
+ /* global WebAssembly, SharedArrayBuffer, console */
23
23
/* eslint-disable no-restricted-globals */
24
24
'use strict' ;
25
25
26
26
module . exports = function ( ) {
27
+ const {
28
+ defineProperty,
29
+ freeze,
30
+ getOwnPropertyDescriptor,
31
+ getOwnPropertyDescriptors,
32
+ getOwnPropertyNames,
33
+ getOwnPropertySymbols,
34
+ getPrototypeOf
35
+ } = Object ;
36
+ const objectHasOwnProperty = Object . prototype . hasOwnProperty ;
37
+ const { ownKeys } = Reflect ;
27
38
const {
28
39
clearImmediate,
29
40
clearInterval,
@@ -33,30 +44,112 @@ module.exports = function() {
33
44
setTimeout
34
45
} = require ( 'timers' ) ;
35
46
47
+ const intrinsicPrototypes = [
48
+ // Anonymous Intrinsics
49
+ // IteratorPrototype
50
+ getPrototypeOf (
51
+ getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) )
52
+ ) ,
53
+ // ArrayIteratorPrototype
54
+ getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) ) ,
55
+ // StringIteratorPrototype
56
+ getPrototypeOf ( new String ( ) [ Symbol . iterator ] ( ) ) ,
57
+ // MapIteratorPrototype
58
+ getPrototypeOf ( new Map ( ) [ Symbol . iterator ] ( ) ) ,
59
+ // SetIteratorPrototype
60
+ getPrototypeOf ( new Set ( ) [ Symbol . iterator ] ( ) ) ,
61
+ // GeneratorFunction
62
+ getPrototypeOf ( function * ( ) { } ) ,
63
+ // AsyncFunction
64
+ getPrototypeOf ( async function ( ) { } ) ,
65
+ // AsyncGeneratorFunction
66
+ getPrototypeOf ( async function * ( ) { } ) ,
67
+ // TypedArray
68
+ getPrototypeOf ( Uint8Array ) ,
69
+
70
+ // 19 Fundamental Objects
71
+ Object . prototype , // 19.1
72
+ Function . prototype , // 19.2
73
+ Boolean . prototype , // 19.3
74
+
75
+ Error . prototype , // 19.5
76
+ EvalError . prototype ,
77
+ RangeError . prototype ,
78
+ ReferenceError . prototype ,
79
+ SyntaxError . prototype ,
80
+ TypeError . prototype ,
81
+ URIError . prototype ,
82
+
83
+ // 20 Numbers and Dates
84
+ Number . prototype , // 20.1
85
+ Date . prototype , // 20.3
86
+
87
+ // 21 Text Processing
88
+ String . prototype , // 21.1
89
+ RegExp . prototype , // 21.2
90
+
91
+ // 22 Indexed Collections
92
+ Array . prototype , // 22.1
93
+
94
+ Int8Array . prototype ,
95
+ Uint8Array . prototype ,
96
+ Uint8ClampedArray . prototype ,
97
+ Int16Array . prototype ,
98
+ Uint16Array . prototype ,
99
+ Int32Array . prototype ,
100
+ Uint32Array . prototype ,
101
+ Float32Array . prototype ,
102
+ Float64Array . prototype ,
103
+ BigInt64Array . prototype ,
104
+ BigUint64Array . prototype ,
105
+
106
+ // 23 Keyed Collections
107
+ Map . prototype , // 23.1
108
+ Set . prototype , // 23.2
109
+ WeakMap . prototype , // 23.3
110
+ WeakSet . prototype , // 23.4
111
+
112
+ // 24 Structured Data
113
+ ArrayBuffer . prototype , // 24.1
114
+ DataView . prototype , // 24.3
115
+ Promise . prototype , // 25.4
116
+
117
+ // Other APIs / Web Compatibility
118
+ console . Console . prototype ,
119
+ BigInt . prototype ,
120
+ WebAssembly . Module . prototype ,
121
+ WebAssembly . Instance . prototype ,
122
+ WebAssembly . Table . prototype ,
123
+ WebAssembly . Memory . prototype ,
124
+ WebAssembly . CompileError . prototype ,
125
+ WebAssembly . LinkError . prototype ,
126
+ WebAssembly . RuntimeError . prototype ,
127
+ SharedArrayBuffer . prototype
128
+ ] ;
36
129
const intrinsics = [
37
130
// Anonymous Intrinsics
38
131
// ThrowTypeError
39
- Object . getOwnPropertyDescriptor ( Function . prototype , 'caller' ) . get ,
132
+ getOwnPropertyDescriptor ( Function . prototype , 'caller' ) . get ,
40
133
// IteratorPrototype
41
- Object . getPrototypeOf (
42
- Object . getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) )
134
+ getPrototypeOf (
135
+ getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) )
43
136
) ,
44
137
// ArrayIteratorPrototype
45
- Object . getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) ) ,
138
+ getPrototypeOf ( new Array ( ) [ Symbol . iterator ] ( ) ) ,
46
139
// StringIteratorPrototype
47
- Object . getPrototypeOf ( new String ( ) [ Symbol . iterator ] ( ) ) ,
140
+ getPrototypeOf ( new String ( ) [ Symbol . iterator ] ( ) ) ,
48
141
// MapIteratorPrototype
49
- Object . getPrototypeOf ( new Map ( ) [ Symbol . iterator ] ( ) ) ,
142
+ getPrototypeOf ( new Map ( ) [ Symbol . iterator ] ( ) ) ,
50
143
// SetIteratorPrototype
51
- Object . getPrototypeOf ( new Set ( ) [ Symbol . iterator ] ( ) ) ,
144
+ getPrototypeOf ( new Set ( ) [ Symbol . iterator ] ( ) ) ,
52
145
// GeneratorFunction
53
- Object . getPrototypeOf ( function * ( ) { } ) ,
146
+ getPrototypeOf ( function * ( ) { } ) ,
54
147
// AsyncFunction
55
- Object . getPrototypeOf ( async function ( ) { } ) ,
148
+ getPrototypeOf ( async function ( ) { } ) ,
56
149
// AsyncGeneratorFunction
57
- Object . getPrototypeOf ( async function * ( ) { } ) ,
150
+ getPrototypeOf ( async function * ( ) { } ) ,
58
151
// TypedArray
59
- Object . getPrototypeOf ( Uint8Array ) ,
152
+ getPrototypeOf ( Uint8Array ) ,
60
153
61
154
// 18 The Global Object
62
155
eval ,
@@ -75,14 +168,13 @@ module.exports = function() {
75
168
Boolean , // 19.3
76
169
Symbol , // 19.4
77
170
78
- // Disabled pending stack trace mutation handling
79
- // Error, // 19.5
80
- // EvalError,
81
- // RangeError,
82
- // ReferenceError,
83
- // SyntaxError,
84
- // TypeError,
85
- // URIError,
171
+ Error , // 19.5
172
+ EvalError ,
173
+ RangeError ,
174
+ ReferenceError ,
175
+ SyntaxError ,
176
+ TypeError ,
177
+ URIError ,
86
178
87
179
// 20 Numbers and Dates
88
180
Number , // 20.1
@@ -128,36 +220,37 @@ module.exports = function() {
128
220
escape ,
129
221
unescape ,
130
222
131
- // Web compatibility
223
+ // Other APIs / Web Compatibility
132
224
clearImmediate ,
133
225
clearInterval ,
134
226
clearTimeout ,
135
227
setImmediate ,
136
228
setInterval ,
137
229
setTimeout ,
138
-
139
- // Other APIs
230
+ console ,
140
231
BigInt ,
141
232
Atomics ,
142
233
WebAssembly ,
143
234
SharedArrayBuffer
144
235
] ;
145
236
146
- if ( typeof Intl !== 'undefined' )
237
+ if ( typeof Intl !== 'undefined' ) {
238
+ intrinsicPrototypes . push ( Intl . Collator . prototype ) ;
239
+ intrinsicPrototypes . push ( Intl . DateTimeFormat . prototype ) ;
240
+ intrinsicPrototypes . push ( Intl . ListFormat . prototype ) ;
241
+ intrinsicPrototypes . push ( Intl . NumberFormat . prototype ) ;
242
+ intrinsicPrototypes . push ( Intl . PluralRules . prototype ) ;
243
+ intrinsicPrototypes . push ( Intl . RelativeTimeFormat . prototype ) ;
147
244
intrinsics . push ( Intl ) ;
245
+ }
246
+
247
+ intrinsicPrototypes . forEach ( enableDerivedOverrides ) ;
148
248
249
+ const frozenSet = new WeakSet ( ) ;
149
250
intrinsics . forEach ( deepFreeze ) ;
150
251
252
+ // Objects that are deeply frozen.
151
253
function deepFreeze ( root ) {
152
-
153
- const { freeze, getOwnPropertyDescriptors, getPrototypeOf } = Object ;
154
- const { ownKeys } = Reflect ;
155
-
156
- // Objects that are deeply frozen.
157
- // It turns out that Error is reachable from WebAssembly so it is
158
- // explicitly added here to ensure it is not frozen
159
- const frozenSet = new WeakSet ( [ Error , Error . prototype ] ) ;
160
-
161
254
/**
162
255
* "innerDeepFreeze()" acts like "Object.freeze()", except that:
163
256
*
@@ -246,4 +339,79 @@ module.exports = function() {
246
339
innerDeepFreeze ( root ) ;
247
340
return root ;
248
341
}
342
+
343
+ /**
344
+ * For a special set of properties (defined below), it ensures that the
345
+ * effect of freezing does not suppress the ability to override these
346
+ * properties on derived objects by simple assignment.
347
+ *
348
+ * Because of lack of sufficient foresight at the time, ES5 unfortunately
349
+ * specified that a simple assignment to a non-existent property must fail if
350
+ * it would override a non-writable data property of the same name. (In
351
+ * retrospect, this was a mistake, but it is now too late and we must live
352
+ * with the consequences.) As a result, simply freezing an object to make it
353
+ * tamper proof has the unfortunate side effect of breaking previously correct
354
+ * code that is considered to have followed JS best practices, if this
355
+ * previous code used assignment to override.
356
+ *
357
+ * To work around this mistake, deepFreeze(), prior to freezing, replaces
358
+ * selected configurable own data properties with accessor properties which
359
+ * simulate what we should have specified -- that assignments to derived
360
+ * objects succeed if otherwise possible.
361
+ */
362
+ function enableDerivedOverride ( obj , prop , desc ) {
363
+ if ( 'value' in desc && desc . configurable ) {
364
+ const value = desc . value ;
365
+
366
+ function getter ( ) {
367
+ return value ;
368
+ }
369
+
370
+ // Re-attach the data property on the object so
371
+ // it can be found by the deep-freeze traversal process.
372
+ getter . value = value ;
373
+
374
+ function setter ( newValue ) {
375
+ if ( obj === this ) {
376
+ // eslint-disable-next-line no-restricted-syntax
377
+ throw new TypeError (
378
+ `Cannot assign to read only property '${ prop } ' of object '${ obj } '`
379
+ ) ;
380
+ }
381
+ if ( objectHasOwnProperty . call ( this , prop ) ) {
382
+ this [ prop ] = newValue ;
383
+ } else {
384
+ defineProperty ( this , prop , {
385
+ value : newValue ,
386
+ writable : true ,
387
+ enumerable : desc . enumerable ,
388
+ configurable : desc . configurable
389
+ } ) ;
390
+ }
391
+ }
392
+
393
+ defineProperty ( obj , prop , {
394
+ get : getter ,
395
+ set : setter ,
396
+ enumerable : desc . enumerable ,
397
+ configurable : desc . configurable
398
+ } ) ;
399
+ }
400
+ }
401
+
402
+ function enableDerivedOverrides ( obj ) {
403
+ if ( ! obj ) {
404
+ return ;
405
+ }
406
+ const descs = getOwnPropertyDescriptors ( obj ) ;
407
+ if ( ! descs ) {
408
+ return ;
409
+ }
410
+ getOwnPropertyNames ( obj ) . forEach ( ( prop ) => {
411
+ return enableDerivedOverride ( obj , prop , descs [ prop ] ) ;
412
+ } ) ;
413
+ getOwnPropertySymbols ( obj ) . forEach ( ( prop ) => {
414
+ return enableDerivedOverride ( obj , prop , descs [ prop ] ) ;
415
+ } ) ;
416
+ }
249
417
} ;
0 commit comments