Skip to content

Commit b9198d9

Browse files
aduh95targos
authored andcommitted
lib: refactor to avoid unsafe regex primordials
PR-URL: #43475 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Stephen Belanger <[email protected]>
1 parent deaf4bb commit b9198d9

39 files changed

+206
-208
lines changed

lib/_http_client.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const {
3131
ObjectKeys,
3232
ObjectSetPrototypeOf,
3333
ReflectApply,
34-
RegExpPrototypeTest,
34+
RegExpPrototypeExec,
3535
String,
3636
StringPrototypeCharCodeAt,
3737
StringPrototypeIncludes,
@@ -165,7 +165,7 @@ function ClientRequest(input, options, cb) {
165165

166166
if (options.path) {
167167
const path = String(options.path);
168-
if (RegExpPrototypeTest(INVALID_PATH_REGEX, path))
168+
if (RegExpPrototypeExec(INVALID_PATH_REGEX, path) !== null)
169169
throw new ERR_UNESCAPED_CHARACTERS('Request path');
170170
}
171171

lib/_http_common.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
const {
2525
MathMin,
2626
Symbol,
27-
RegExpPrototypeTest,
27+
RegExpPrototypeExec,
2828
} = primordials;
2929
const { setImmediate } = require('timers');
3030

@@ -207,7 +207,7 @@ const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
207207
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
208208
*/
209209
function checkIsHttpToken(val) {
210-
return RegExpPrototypeTest(tokenRegExp, val);
210+
return RegExpPrototypeExec(tokenRegExp, val) !== null;
211211
}
212212

213213
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
@@ -218,7 +218,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
218218
* field-vchar = VCHAR / obs-text
219219
*/
220220
function checkInvalidHeaderChar(val) {
221-
return RegExpPrototypeTest(headerCharRegex, val);
221+
return RegExpPrototypeExec(headerCharRegex, val) !== null;
222222
}
223223

224224
function cleanParser(parser) {

lib/_http_outgoing.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const {
3333
ObjectValues,
3434
ObjectPrototypeHasOwnProperty,
3535
ObjectSetPrototypeOf,
36-
RegExpPrototypeTest,
36+
RegExpPrototypeExec,
3737
SafeSet,
3838
StringPrototypeToLowerCase,
3939
Symbol,
@@ -542,15 +542,15 @@ function matchHeader(self, state, field, value) {
542542
case 'connection':
543543
state.connection = true;
544544
self._removedConnection = false;
545-
if (RegExpPrototypeTest(RE_CONN_CLOSE, value))
545+
if (RegExpPrototypeExec(RE_CONN_CLOSE, value) !== null)
546546
self._last = true;
547547
else
548548
self.shouldKeepAlive = true;
549549
break;
550550
case 'transfer-encoding':
551551
state.te = true;
552552
self._removedTE = false;
553-
if (RegExpPrototypeTest(RE_TE_CHUNKED, value))
553+
if (RegExpPrototypeExec(RE_TE_CHUNKED, value) !== null)
554554
self.chunkedEncoding = true;
555555
break;
556556
case 'content-length':

lib/_http_server.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const {
2626
Error,
2727
ObjectKeys,
2828
ObjectSetPrototypeOf,
29-
RegExpPrototypeTest,
29+
RegExpPrototypeExec,
3030
ReflectApply,
3131
Symbol,
3232
SymbolFor,
@@ -192,8 +192,8 @@ function ServerResponse(req) {
192192
this._expect_continue = false;
193193

194194
if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
195-
this.useChunkedEncodingByDefault = RegExpPrototypeTest(chunkExpression,
196-
req.headers.te);
195+
this.useChunkedEncodingByDefault = RegExpPrototypeExec(chunkExpression,
196+
req.headers.te) !== null;
197197
this.shouldKeepAlive = false;
198198
}
199199

@@ -987,7 +987,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
987987
} else if (req.headers.expect !== undefined) {
988988
handled = true;
989989

990-
if (RegExpPrototypeTest(continueExpression, req.headers.expect)) {
990+
if (RegExpPrototypeExec(continueExpression, req.headers.expect) !== null) {
991991
res._expect_continue = true;
992992

993993
if (server.listenerCount('checkContinue') > 0) {

lib/_tls_wrap.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ const {
3131
ObjectSetPrototypeOf,
3232
ReflectApply,
3333
RegExp,
34-
RegExpPrototypeTest,
35-
StringPrototypeReplace,
34+
RegExpPrototypeExec,
35+
RegExpPrototypeSymbolReplace,
36+
StringPrototypeReplaceAll,
3637
StringPrototypeSlice,
3738
Symbol,
3839
SymbolFor,
@@ -425,8 +426,8 @@ function onerror(err) {
425426
owner.destroy(err);
426427
} else if (owner._tlsOptions?.isServer &&
427428
owner._rejectUnauthorized &&
428-
RegExpPrototypeTest(/peer did not return a certificate/,
429-
err.message)) {
429+
RegExpPrototypeExec(/peer did not return a certificate/,
430+
err.message) !== null) {
430431
// Ignore server's authorization errors
431432
owner.destroy();
432433
} else {
@@ -1447,9 +1448,9 @@ Server.prototype.addContext = function(servername, context) {
14471448
throw new ERR_TLS_REQUIRED_SERVER_NAME();
14481449
}
14491450

1450-
const re = new RegExp('^' + StringPrototypeReplace(
1451-
StringPrototypeReplace(servername, /([.^$+?\-\\[\]{}])/g, '\\$1'),
1452-
/\*/g, '[^.]*'
1451+
const re = new RegExp('^' + StringPrototypeReplaceAll(
1452+
RegExpPrototypeSymbolReplace(/([.^$+?\-\\[\]{}])/g, servername, '\\$1'),
1453+
'*', '[^.]*'
14531454
) + '$');
14541455
ArrayPrototypePush(this._contexts,
14551456
[re, tls.createSecureContext(context).context]);
@@ -1473,7 +1474,7 @@ function SNICallback(servername, callback) {
14731474

14741475
for (let i = contexts.length - 1; i >= 0; --i) {
14751476
const elem = contexts[i];
1476-
if (RegExpPrototypeTest(elem[0], servername)) {
1477+
if (RegExpPrototypeExec(elem[0], servername) !== null) {
14771478
callback(null, elem[1]);
14781479
return;
14791480
}

lib/assert.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const {
3535
ObjectKeys,
3636
ObjectPrototypeIsPrototypeOf,
3737
ReflectApply,
38-
RegExpPrototypeTest,
38+
RegExpPrototypeExec,
39+
RegExpPrototypeSymbolReplace,
3940
SafeMap,
4041
String,
4142
StringPrototypeCharCodeAt,
@@ -345,7 +346,7 @@ function getErrMessage(message, fn) {
345346
// Always normalize indentation, otherwise the message could look weird.
346347
if (StringPrototypeIncludes(message, '\n')) {
347348
if (EOL === '\r\n') {
348-
message = StringPrototypeReplace(message, /\r\n/g, '\n');
349+
message = RegExpPrototypeSymbolReplace(/\r\n/g, message, '\n');
349350
}
350351
const frames = StringPrototypeSplit(message, '\n');
351352
message = ArrayPrototypeShift(frames);
@@ -606,7 +607,7 @@ class Comparison {
606607
if (actual !== undefined &&
607608
typeof actual[key] === 'string' &&
608609
isRegExp(obj[key]) &&
609-
RegExpPrototypeTest(obj[key], actual[key])) {
610+
RegExpPrototypeExec(obj[key], actual[key]) !== null) {
610611
this[key] = actual[key];
611612
} else {
612613
this[key] = obj[key];
@@ -652,7 +653,7 @@ function expectedException(actual, expected, message, fn) {
652653
// Handle regular expressions.
653654
if (isRegExp(expected)) {
654655
const str = String(actual);
655-
if (RegExpPrototypeTest(expected, str))
656+
if (RegExpPrototypeExec(expected, str) !== null)
656657
return;
657658

658659
if (!message) {
@@ -687,7 +688,7 @@ function expectedException(actual, expected, message, fn) {
687688
for (const key of keys) {
688689
if (typeof actual[key] === 'string' &&
689690
isRegExp(expected[key]) &&
690-
RegExpPrototypeTest(expected[key], actual[key])) {
691+
RegExpPrototypeExec(expected[key], actual[key]) !== null) {
691692
continue;
692693
}
693694
compareExceptionKey(actual, expected, key, message, keys, fn);
@@ -851,7 +852,7 @@ function hasMatchingError(actual, expected) {
851852
if (typeof expected !== 'function') {
852853
if (isRegExp(expected)) {
853854
const str = String(actual);
854-
return RegExpPrototypeTest(expected, str);
855+
return RegExpPrototypeExec(expected, str) !== null;
855856
}
856857
throw new ERR_INVALID_ARG_TYPE(
857858
'expected', ['Function', 'RegExp'], expected
@@ -1000,7 +1001,7 @@ function internalMatch(string, regexp, message, fn) {
10001001
}
10011002
const match = fn === assert.match;
10021003
if (typeof string !== 'string' ||
1003-
RegExpPrototypeTest(regexp, string) !== match) {
1004+
RegExpPrototypeExec(regexp, string) !== null !== match) {
10041005
if (message instanceof Error) {
10051006
throw message;
10061007
}

lib/buffer.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ const {
3737
ObjectDefineProperties,
3838
ObjectDefineProperty,
3939
ObjectSetPrototypeOf,
40+
RegExpPrototypeSymbolReplace,
4041
StringPrototypeCharCodeAt,
41-
StringPrototypeReplace,
4242
StringPrototypeSlice,
4343
StringPrototypeToLowerCase,
4444
StringPrototypeTrim,
@@ -837,8 +837,8 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
837837
const max = INSPECT_MAX_BYTES;
838838
const actualMax = MathMin(max, this.length);
839839
const remaining = this.length - max;
840-
let str = StringPrototypeTrim(StringPrototypeReplace(
841-
this.hexSlice(0, actualMax), /(.{2})/g, '$1 '));
840+
let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace(
841+
/(.{2})/g, this.hexSlice(0, actualMax), '$1 '));
842842
if (remaining > 0)
843843
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
844844
// Inspect special properties as well, if possible.

lib/child_process.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const {
3636
ObjectAssign,
3737
ObjectDefineProperty,
3838
ObjectPrototypeHasOwnProperty,
39-
RegExpPrototypeTest,
39+
RegExpPrototypeExec,
4040
SafeSet,
4141
StringPrototypeSlice,
4242
StringPrototypeToUpperCase,
@@ -571,7 +571,7 @@ function normalizeSpawnArguments(file, args, options) {
571571
else
572572
file = process.env.comspec || 'cmd.exe';
573573
// '/d /s /c' is used only for cmd.exe.
574-
if (RegExpPrototypeTest(/^(?:.*\\)?cmd(?:\.exe)?$/i, file)) {
574+
if (RegExpPrototypeExec(/^(?:.*\\)?cmd(?:\.exe)?$/i, file) !== null) {
575575
args = ['/d', '/s', '/c', `"${command}"`];
576576
windowsVerbatimArguments = true;
577577
} else {

lib/internal/blob.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const {
99
PromiseReject,
1010
SafePromisePrototypeFinally,
1111
ReflectConstruct,
12+
RegExpPrototypeExec,
1213
RegExpPrototypeSymbolReplace,
13-
RegExpPrototypeTest,
1414
StringPrototypeToLowerCase,
1515
StringPrototypeSplit,
1616
Symbol,
@@ -165,7 +165,7 @@ class Blob {
165165
this[kLength] = length;
166166

167167
type = `${type}`;
168-
this[kType] = RegExpPrototypeTest(disallowedTypeCharacters, type) ?
168+
this[kType] = RegExpPrototypeExec(disallowedTypeCharacters, type) !== null ?
169169
'' : StringPrototypeToLowerCase(type);
170170

171171
// eslint-disable-next-line no-constructor-return
@@ -247,7 +247,7 @@ class Blob {
247247
end |= 0;
248248

249249
contentType = `${contentType}`;
250-
if (RegExpPrototypeTest(disallowedTypeCharacters, contentType)) {
250+
if (RegExpPrototypeExec(disallowedTypeCharacters, contentType) !== null) {
251251
contentType = '';
252252
} else {
253253
contentType = StringPrototypeToLowerCase(contentType);

lib/internal/cluster/primary.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const {
66
ArrayPrototypeSome,
77
ObjectKeys,
88
ObjectValues,
9-
RegExpPrototypeTest,
9+
RegExpPrototypeExec,
1010
SafeMap,
1111
StringPrototypeStartsWith,
1212
} = primordials;
@@ -121,8 +121,8 @@ function createWorkerProcess(id, env) {
121121
const nodeOptions = process.env.NODE_OPTIONS || '';
122122

123123
if (ArrayPrototypeSome(execArgv,
124-
(arg) => RegExpPrototypeTest(debugArgRegex, arg)) ||
125-
RegExpPrototypeTest(debugArgRegex, nodeOptions)) {
124+
(arg) => RegExpPrototypeExec(debugArgRegex, arg) !== null) ||
125+
RegExpPrototypeExec(debugArgRegex, nodeOptions) !== null) {
126126
let inspectPort;
127127
if ('inspectPort' in cluster.settings) {
128128
if (typeof cluster.settings.inspectPort === 'function')

lib/internal/console/constructor.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ const {
2424
ReflectApply,
2525
ReflectConstruct,
2626
ReflectOwnKeys,
27+
RegExpPrototypeSymbolReplace,
2728
SafeArrayIterator,
2829
SafeMap,
2930
SafeWeakMap,
3031
StringPrototypeIncludes,
3132
StringPrototypePadStart,
3233
StringPrototypeRepeat,
33-
StringPrototypeReplace,
3434
StringPrototypeSlice,
3535
StringPrototypeSplit,
3636
Symbol,
@@ -279,7 +279,7 @@ ObjectDefineProperties(Console.prototype, {
279279

280280
if (groupIndent.length !== 0) {
281281
if (StringPrototypeIncludes(string, '\n')) {
282-
string = StringPrototypeReplace(string, /\n/g, `\n${groupIndent}`);
282+
string = RegExpPrototypeSymbolReplace(/\n/g, string, `\n${groupIndent}`);
283283
}
284284
string = groupIndent + string;
285285
}

lib/internal/debugger/inspect.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ const {
1515
PromisePrototypeThen,
1616
PromiseResolve,
1717
Proxy,
18-
RegExpPrototypeSymbolMatch,
18+
RegExpPrototypeExec,
1919
RegExpPrototypeSymbolSplit,
20-
RegExpPrototypeTest,
2120
StringPrototypeEndsWith,
2221
StringPrototypeSplit,
2322
} = primordials;
@@ -91,7 +90,7 @@ async function runScript(script, scriptArgs, inspectHost, inspectPort,
9190
return new Promise((resolve) => {
9291
function waitForListenHint(text) {
9392
output += text;
94-
const debug = RegExpPrototypeSymbolMatch(debugRegex, output);
93+
const debug = RegExpPrototypeExec(debugRegex, output);
9594
if (debug) {
9695
const host = debug[1];
9796
const port = Number(debug[2]);
@@ -282,8 +281,8 @@ function parseArgv(args) {
282281
let script = target;
283282
let scriptArgs = args;
284283

285-
const hostMatch = RegExpPrototypeSymbolMatch(/^([^:]+):(\d+)$/, target);
286-
const portMatch = RegExpPrototypeSymbolMatch(/^--port=(\d+)$/, target);
284+
const hostMatch = RegExpPrototypeExec(/^([^:]+):(\d+)$/, target);
285+
const portMatch = RegExpPrototypeExec(/^--port=(\d+)$/, target);
287286

288287
if (hostMatch) {
289288
// Connecting to remote debugger
@@ -296,7 +295,7 @@ function parseArgv(args) {
296295
port = Number(portMatch[1]);
297296
script = args[0];
298297
scriptArgs = ArrayPrototypeSlice(args, 1);
299-
} else if (args.length === 1 && RegExpPrototypeTest(/^\d+$/, args[0]) &&
298+
} else if (args.length === 1 && RegExpPrototypeExec(/^\d+$/, args[0]) !== null &&
300299
target === '-p') {
301300
// Start debugger against a given pid
302301
const pid = Number(args[0]);

lib/internal/debugger/inspect_repl.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const {
2929
PromiseResolve,
3030
ReflectGetOwnPropertyDescriptor,
3131
ReflectOwnKeys,
32-
RegExpPrototypeSymbolMatch,
32+
RegExpPrototypeExec,
3333
RegExpPrototypeSymbolReplace,
3434
SafeArrayIterator,
3535
SafeMap,
@@ -114,7 +114,7 @@ takeHeapSnapshot(filepath = 'node.heapsnapshot')
114114
const FUNCTION_NAME_PATTERN = /^(?:function\*? )?([^(\s]+)\(/;
115115
function extractFunctionName(description) {
116116
const fnNameMatch =
117-
RegExpPrototypeSymbolMatch(FUNCTION_NAME_PATTERN, description);
117+
RegExpPrototypeExec(FUNCTION_NAME_PATTERN, description);
118118
return fnNameMatch ? `: ${fnNameMatch[1]}` : '';
119119
}
120120

@@ -171,7 +171,7 @@ function markSourceColumn(sourceText, position, useColors) {
171171

172172
function extractErrorMessage(stack) {
173173
if (!stack) return '<unknown>';
174-
const m = RegExpPrototypeSymbolMatch(/^\w+: ([^\n]+)/, stack);
174+
const m = RegExpPrototypeExec(/^\w+: ([^\n]+)/, stack);
175175
return m?.[1] ?? stack;
176176
}
177177

@@ -578,7 +578,7 @@ function createRepl(inspector) {
578578
function prepareControlCode(input) {
579579
if (input === '\n') return lastCommand;
580580
// Add parentheses: exec process.title => exec("process.title");
581-
const match = RegExpPrototypeSymbolMatch(/^\s*(?:exec|p)\s+([^\n]*)/, input);
581+
const match = RegExpPrototypeExec(/^\s*(?:exec|p)\s+([^\n]*)/, input);
582582
if (match) {
583583
lastCommand = `exec(${JSONStringify(match[1])})`;
584584
} else {

0 commit comments

Comments
 (0)