1// Flags: --expose-internals 2'use strict'; 3 4const { mustNotCall } = require('../common'); 5const assert = require('assert'); 6 7const { 8 RegExpPrototypeExec, 9 RegExpPrototypeSymbolReplace, 10 RegExpPrototypeSymbolSearch, 11 RegExpPrototypeSymbolSplit, 12 SafeStringPrototypeSearch, 13 hardenRegExp, 14} = require('internal/test/binding').primordials; 15 16const { 17 SideEffectFreeRegExpPrototypeExec, 18 SideEffectFreeRegExpPrototypeSymbolReplace, 19 SideEffectFreeRegExpPrototypeSymbolSplit, 20} = require('internal/util'); 21 22 23Object.defineProperties(RegExp.prototype, { 24 [Symbol.match]: { 25 get: mustNotCall('get %RegExp.prototype%[@@match]'), 26 set: mustNotCall('set %RegExp.prototype%[@@match]'), 27 }, 28 [Symbol.matchAll]: { 29 get: mustNotCall('get %RegExp.prototype%[@@matchAll]'), 30 set: mustNotCall('set %RegExp.prototype%[@@matchAll]'), 31 }, 32 [Symbol.replace]: { 33 get: mustNotCall('get %RegExp.prototype%[@@replace]'), 34 set: mustNotCall('set %RegExp.prototype%[@@replace]'), 35 }, 36 [Symbol.search]: { 37 get: mustNotCall('get %RegExp.prototype%[@@search]'), 38 set: mustNotCall('set %RegExp.prototype%[@@search]'), 39 }, 40 [Symbol.split]: { 41 get: mustNotCall('get %RegExp.prototype%[@@split]'), 42 set: mustNotCall('set %RegExp.prototype%[@@split]'), 43 }, 44 dotAll: { 45 get: mustNotCall('get %RegExp.prototype%.dotAll'), 46 set: mustNotCall('set %RegExp.prototype%.dotAll'), 47 }, 48 exec: { 49 get: mustNotCall('get %RegExp.prototype%.exec'), 50 set: mustNotCall('set %RegExp.prototype%.exec'), 51 }, 52 flags: { 53 get: mustNotCall('get %RegExp.prototype%.flags'), 54 set: mustNotCall('set %RegExp.prototype%.flags'), 55 }, 56 global: { 57 get: mustNotCall('get %RegExp.prototype%.global'), 58 set: mustNotCall('set %RegExp.prototype%.global'), 59 }, 60 hasIndices: { 61 get: mustNotCall('get %RegExp.prototype%.hasIndices'), 62 set: mustNotCall('set %RegExp.prototype%.hasIndices'), 63 }, 64 ignoreCase: { 65 get: mustNotCall('get %RegExp.prototype%.ignoreCase'), 66 set: mustNotCall('set %RegExp.prototype%.ignoreCase'), 67 }, 68 multiline: { 69 get: mustNotCall('get %RegExp.prototype%.multiline'), 70 set: mustNotCall('set %RegExp.prototype%.multiline'), 71 }, 72 source: { 73 get: mustNotCall('get %RegExp.prototype%.source'), 74 set: mustNotCall('set %RegExp.prototype%.source'), 75 }, 76 sticky: { 77 get: mustNotCall('get %RegExp.prototype%.sticky'), 78 set: mustNotCall('set %RegExp.prototype%.sticky'), 79 }, 80 test: { 81 get: mustNotCall('get %RegExp.prototype%.test'), 82 set: mustNotCall('set %RegExp.prototype%.test'), 83 }, 84 toString: { 85 get: mustNotCall('get %RegExp.prototype%.toString'), 86 set: mustNotCall('set %RegExp.prototype%.toString'), 87 }, 88 unicode: { 89 get: mustNotCall('get %RegExp.prototype%.unicode'), 90 set: mustNotCall('set %RegExp.prototype%.unicode'), 91 }, 92}); 93 94hardenRegExp(hardenRegExp(/1/)); 95 96// IMO there are no valid use cases in node core to use RegExpPrototypeSymbolMatch 97// or RegExpPrototypeSymbolMatchAll, they are inherently unsafe. 98 99assert.strictEqual(RegExpPrototypeExec(/foo/, 'bar'), null); 100assert.strictEqual(RegExpPrototypeExec(hardenRegExp(/foo/), 'bar'), null); 101assert.strictEqual(SideEffectFreeRegExpPrototypeExec(/foo/, 'bar'), null); 102assert.strictEqual(SideEffectFreeRegExpPrototypeExec(hardenRegExp(/foo/), 'bar'), null); 103{ 104 const expected = ['bar']; 105 Object.defineProperties(expected, { 106 index: { __proto__: null, configurable: true, writable: true, enumerable: true, value: 0 }, 107 input: { __proto__: null, configurable: true, writable: true, enumerable: true, value: 'bar' }, 108 groups: { __proto__: null, configurable: true, writable: true, enumerable: true }, 109 }); 110 const actual = SideEffectFreeRegExpPrototypeExec(/bar/, 'bar'); 111 112 // assert.deepStrictEqual(actual, expected) doesn't work for cross-realm comparison. 113 114 assert.strictEqual(Array.isArray(actual), Array.isArray(expected)); 115 assert.deepStrictEqual(Reflect.ownKeys(actual), Reflect.ownKeys(expected)); 116 for (const key of Reflect.ownKeys(expected)) { 117 assert.deepStrictEqual( 118 Reflect.getOwnPropertyDescriptor(actual, key), 119 Reflect.getOwnPropertyDescriptor(expected, key), 120 ); 121 } 122} 123{ 124 const myRegex = hardenRegExp(/a/); 125 assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'bear'); 126} 127{ 128 const myRegex = /a/; 129 assert.strictEqual(SideEffectFreeRegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'bear'); 130} 131{ 132 const myRegex = hardenRegExp(/a/g); 133 assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'beer'); 134} 135{ 136 const myRegex = /a/g; 137 assert.strictEqual(SideEffectFreeRegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'beer'); 138} 139{ 140 const myRegex = hardenRegExp(/a/); 141 assert.strictEqual(RegExpPrototypeSymbolSearch(myRegex, 'baar'), 1); 142} 143{ 144 const myRegex = /a/; 145 assert.strictEqual(SafeStringPrototypeSearch('baar', myRegex), 1); 146} 147{ 148 const myRegex = hardenRegExp(/a/); 149 assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 0), []); 150} 151{ 152 const myRegex = /a/; 153 const expected = []; 154 const actual = SideEffectFreeRegExpPrototypeSymbolSplit(myRegex, 'baar', 0); 155 156 // assert.deepStrictEqual(actual, expected) doesn't work for cross-realm comparison. 157 158 assert.strictEqual(Array.isArray(actual), Array.isArray(expected)); 159 assert.deepStrictEqual(Reflect.ownKeys(actual), Reflect.ownKeys(expected)); 160 for (const key of Reflect.ownKeys(expected)) { 161 assert.deepStrictEqual( 162 Reflect.getOwnPropertyDescriptor(actual, key), 163 Reflect.getOwnPropertyDescriptor(expected, key), 164 ); 165 } 166} 167{ 168 const myRegex = hardenRegExp(/a/); 169 assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 1), ['b']); 170} 171{ 172 const myRegex = hardenRegExp(/a/); 173 assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar'), ['b', '', 'r']); 174} 175