Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: avoid unsafe String methods that depend on RegExp prototype methods #36593

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 10 additions & 8 deletions lib/_tls_common.js
Expand Up @@ -26,7 +26,7 @@ const tls = require('tls');
const {
ArrayPrototypePush,
ObjectCreate,
StringPrototypeReplace,
RegExpPrototypeSymbolReplace,
} = primordials;

const {
Expand Down Expand Up @@ -135,13 +135,15 @@ function translatePeerCertificate(c) {
c.infoAccess = ObjectCreate(null);

// XXX: More key validation?
StringPrototypeReplace(info, /([^\n:]*):([^\n]*)(?:\n|$)/g,
(all, key, val) => {
if (key in c.infoAccess)
ArrayPrototypePush(c.infoAccess[key], val);
else
c.infoAccess[key] = [val];
});
RegExpPrototypeSymbolReplace(
/([^\n:]*):([^\n]*)(?:\n|$)/g,
info,
(all, key, val) => {
if (key in c.infoAccess)
ArrayPrototypePush(c.infoAccess[key], val);
else
c.infoAccess[key] = [val];
});
}
return c;
}
Expand Down
10 changes: 6 additions & 4 deletions lib/_tls_wrap.js
Expand Up @@ -31,8 +31,9 @@ const {
ObjectSetPrototypeOf,
ReflectApply,
RegExp,
RegExpPrototypeSymbolReplace,
RegExpPrototypeTest,
StringPrototypeReplace,
StringPrototypeReplaceAll,
StringPrototypeSlice,
Symbol,
SymbolFor,
Expand Down Expand Up @@ -1444,9 +1445,10 @@ Server.prototype.addContext = function(servername, context) {
throw new ERR_TLS_REQUIRED_SERVER_NAME();
}

const re = new RegExp('^' + StringPrototypeReplace(
StringPrototypeReplace(servername, /([.^$+?\-\\[\]{}])/g, '\\$1'),
/\*/g, '[^.]*'
const re = new RegExp('^' + StringPrototypeReplaceAll(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.prototype.replaceAll is not available to primordials because it can be disabled by --no-harmony-string-replaceall

RegExpPrototypeSymbolReplace(/([.^$+?\-\\[\]{}])/g, servername, '\\$1'),
'*',
'[^.]*',
) + '$');
ArrayPrototypePush(this._contexts,
[re, tls.createSecureContext(context).context]);
Expand Down
12 changes: 7 additions & 5 deletions lib/assert.js
Expand Up @@ -35,13 +35,14 @@ const {
ObjectKeys,
ObjectPrototypeIsPrototypeOf,
ReflectApply,
RegExpPrototypeSymbolReplace,
RegExpPrototypeTest,
SafeMap,
String,
StringPrototypeCharCodeAt,
StringPrototypeIncludes,
StringPrototypeIndexOf,
StringPrototypeReplace,
StringPrototypeReplaceAll,
StringPrototypeSlice,
StringPrototypeSplit,
StringPrototypeStartsWith,
Expand Down Expand Up @@ -271,9 +272,10 @@ function parseCode(code, offset) {

return [
node.node.start,
StringPrototypeReplace(StringPrototypeSlice(code,
node.node.start, node.node.end),
escapeSequencesRegExp, escapeFn),
RegExpPrototypeSymbolReplace(
escapeSequencesRegExp,
StringPrototypeSlice(code, node.node.start, node.node.end),
escapeFn),
];
}

Expand Down Expand Up @@ -346,7 +348,7 @@ function getErrMessage(message, fn) {
// Always normalize indentation, otherwise the message could look weird.
if (StringPrototypeIncludes(message, '\n')) {
if (EOL === '\r\n') {
message = StringPrototypeReplace(message, /\r\n/g, '\n');
message = StringPrototypeReplaceAll(message, '\r\n', '\n');
}
const frames = StringPrototypeSplit(message, '\n');
message = ArrayPrototypeShift(frames);
Expand Down
6 changes: 3 additions & 3 deletions lib/buffer.js
Expand Up @@ -36,8 +36,8 @@ const {
ObjectDefineProperties,
ObjectDefineProperty,
ObjectSetPrototypeOf,
RegExpPrototypeSymbolReplace,
StringPrototypeCharCodeAt,
StringPrototypeReplace,
StringPrototypeSlice,
StringPrototypeToLowerCase,
StringPrototypeTrim,
Expand Down Expand Up @@ -832,8 +832,8 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
const max = INSPECT_MAX_BYTES;
const actualMax = MathMin(max, this.length);
const remaining = this.length - max;
let str = StringPrototypeTrim(StringPrototypeReplace(
this.hexSlice(0, actualMax), /(.{2})/g, '$1 '));
let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace(
/(.{2})/g, this.hexSlice(0, actualMax), '$1 '));
if (remaining > 0)
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
// Inspect special properties as well, if possible.
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/console/constructor.js
Expand Up @@ -29,7 +29,7 @@ const {
StringPrototypeIncludes,
StringPrototypePadStart,
StringPrototypeRepeat,
StringPrototypeReplace,
StringPrototypeReplaceAll,
StringPrototypeSlice,
StringPrototypeSplit,
Symbol,
Expand Down Expand Up @@ -265,7 +265,7 @@ ObjectDefineProperties(Console.prototype, {

if (groupIndent.length !== 0) {
if (StringPrototypeIncludes(string, '\n')) {
string = StringPrototypeReplace(string, /\n/g, `\n${groupIndent}`);
string = StringPrototypeReplaceAll(string, '\n', `\n${groupIndent}`);
}
string = groupIndent + string;
}
Expand Down
11 changes: 6 additions & 5 deletions lib/internal/dns/utils.js
Expand Up @@ -7,8 +7,8 @@ const {
ArrayPrototypePush,
FunctionPrototypeBind,
NumberParseInt,
StringPrototypeMatch,
StringPrototypeReplace,
RegExpPrototypeExec,
RegExpPrototypeSymbolReplace,
} = primordials;

const errors = require('internal/errors');
Expand Down Expand Up @@ -86,21 +86,22 @@ class Resolver {
if (ipVersion !== 0)
return ArrayPrototypePush(newSet, [ipVersion, serv, IANA_DNS_PORT]);

const match = StringPrototypeMatch(serv, IPv6RE);
const match = RegExpPrototypeExec(IPv6RE, serv);

// Check for an IPv6 in brackets.
if (match) {
ipVersion = isIP(match[1]);

if (ipVersion !== 0) {
const port = NumberParseInt(
StringPrototypeReplace(serv, addrSplitRE, '$2')) || IANA_DNS_PORT;
RegExpPrototypeSymbolReplace(addrSplitRE, serv, '$2')
) || IANA_DNS_PORT;
return ArrayPrototypePush(newSet, [ipVersion, match[1], port]);
}
}

// addr::port
const addrSplitMatch = StringPrototypeMatch(serv, addrSplitRE);
const addrSplitMatch = RegExpPrototypeExec(addrSplitRE, serv);

if (addrSplitMatch) {
const hostIP = addrSplitMatch[1];
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/errors.js
Expand Up @@ -41,14 +41,14 @@ const {
ObjectPrototypeHasOwnProperty,
RangeError,
ReflectApply,
RegExpPrototypeExec,
RegExpPrototypeTest,
SafeArrayIterator,
SafeMap,
SafeWeakMap,
String,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeMatch,
StringPrototypeSlice,
StringPrototypeSplit,
StringPrototypeStartsWith,
Expand Down Expand Up @@ -422,7 +422,7 @@ function getMessage(key, args, self) {
}

const expectedLength =
(StringPrototypeMatch(msg, /%[dfijoOs]/g) || []).length;
(RegExpPrototypeExec(/%[dfijoOs]/g, msg) || []).length;
assert(
expectedLength === args.length,
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/fs/utils.js
Expand Up @@ -19,7 +19,7 @@ const {
ReflectOwnKeys,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeReplace,
StringPrototypeReplaceAll,
Symbol,
TypedArrayPrototypeIncludes,
} = primordials;
Expand Down Expand Up @@ -393,7 +393,7 @@ function preprocessSymlinkDestination(path, type, linkPath) {
return pathModule.toNamespacedPath(path);
}
// Windows symlinks don't tolerate forward slashes.
return StringPrototypeReplace(path, /\//g, '\\');
return StringPrototypeReplaceAll(path, '/', '\\');
}

// Constructor for file stats.
Expand Down
12 changes: 6 additions & 6 deletions lib/internal/main/print_help.js
Expand Up @@ -8,11 +8,11 @@ const {
MathMax,
ObjectKeys,
RegExp,
RegExpPrototypeSymbolReplace,
StringPrototypeLocaleCompare,
StringPrototypeSlice,
StringPrototypeTrimLeft,
StringPrototypeRepeat,
StringPrototypeReplace,
SafeMap,
} = primordials;

Expand Down Expand Up @@ -77,14 +77,14 @@ const envVars = new SafeMap(ArrayPrototypeConcat([


function indent(text, depth) {
return StringPrototypeReplace(text, /^/gm, StringPrototypeRepeat(' ', depth));
return RegExpPrototypeSymbolReplace(/^/gm, text, StringPrototypeRepeat(' ', depth));
}

function fold(text, width) {
return StringPrototypeReplace(text,
new RegExp(`([^\n]{0,${width}})( |$)`, 'g'),
(_, newLine, end) =>
newLine + (end === ' ' ? '\n' : ''));
return RegExpPrototypeSymbolReplace(
new RegExp(`([^\n]{0,${width}})( |$)`, 'g'),
text,
(_, newLine, end) => newLine + (end === ' ' ? '\n' : ''));
}

function getArgDescription(type) {
Expand Down
3 changes: 1 addition & 2 deletions lib/internal/modules/cjs/loader.js
Expand Up @@ -58,7 +58,6 @@ const {
StringPrototypeEndsWith,
StringPrototypeLastIndexOf,
StringPrototypeIndexOf,
StringPrototypeMatch,
StringPrototypeRepeat,
StringPrototypeSlice,
StringPrototypeSplit,
Expand Down Expand Up @@ -472,7 +471,7 @@ const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
function resolveExports(nmPath, request) {
// The implementation's behavior is meant to mirror resolution in ESM.
const { 1: name, 2: expansion = '' } =
StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
RegExpPrototypeExec(EXPORTS_PATTERN, request) || [];
if (!name)
return;
const pkgPath = path.resolve(nmPath, name);
Expand Down
18 changes: 9 additions & 9 deletions lib/internal/modules/esm/module_job.js
Expand Up @@ -12,12 +12,12 @@ const {
PromiseResolve,
PromisePrototypeCatch,
ReflectApply,
RegExpPrototypeExec,
RegExpPrototypeTest,
RegExpPrototypeSymbolReplace,
SafeArrayIterator,
SafeSet,
StringPrototypeIncludes,
StringPrototypeMatch,
StringPrototypeReplace,
StringPrototypeSplit,
StringPrototypeStartsWith,
} = primordials;
Expand Down Expand Up @@ -136,14 +136,14 @@ class ModuleJob {
StringPrototypeIncludes(e.message,
' does not provide an export named')) {
const splitStack = StringPrototypeSplit(e.stack, '\n');
const parentFileUrl = StringPrototypeReplace(
splitStack[0],
const parentFileUrl = RegExpPrototypeSymbolReplace(
/:\d+$/,
splitStack[0],
''
);
const { 1: childSpecifier, 2: name } = StringPrototypeMatch(
e.message,
/module '(.*)' does not provide an export named '(.+)'/);
const { 1: childSpecifier, 2: name } = RegExpPrototypeExec(
/module '(.*)' does not provide an export named '(.+)'/,
e.message);
const { url: childFileURL } = await this.loader.resolve(
childSpecifier, parentFileUrl,
);
Expand All @@ -162,9 +162,9 @@ class ModuleJob {
// line which causes the error. For multi-line import statements we
// cannot generate an equivalent object destructuring assignment by
// just parsing the error stack.
const oneLineNamedImports = StringPrototypeMatch(importStatement, /{.*}/);
const oneLineNamedImports = RegExpPrototypeExec(/{.*}/, importStatement);
const destructuringAssignment = oneLineNamedImports &&
StringPrototypeReplace(oneLineNamedImports, /\s+as\s+/g, ': ');
RegExpPrototypeSymbolReplace(/\s+as\s+/g, oneLineNamedImports, ': ');
e.message = `Named export '${name}' not found. The requested module` +
` '${childSpecifier}' is a CommonJS module, which may not support` +
' all module.exports as named exports.\nCommonJS modules can ' +
Expand Down
7 changes: 3 additions & 4 deletions lib/internal/modules/esm/translators.js
Expand Up @@ -13,7 +13,7 @@ const {
SafeArrayIterator,
SafeMap,
SafeSet,
StringPrototypeReplace,
StringPrototypeReplaceAll,
StringPrototypeSlice,
StringPrototypeStartsWith,
SyntaxErrorPrototype,
Expand Down Expand Up @@ -164,14 +164,13 @@ function enrichCJSError(err, content, filename) {

// Strategy for loading a node-style CommonJS module
const isWindows = process.platform === 'win32';
const winSepRegEx = /\//g;
translators.set('commonjs', async function commonjsStrategy(url, source,
isMain) {
debug(`Translating CJSModule ${url}`);

let filename = internalURLModule.fileURLToPath(new URL(url));
if (isWindows)
filename = StringPrototypeReplace(filename, winSepRegEx, '\\');
filename = StringPrototypeReplaceAll(filename, '/', '\\');

if (!cjsParse) await initCJSParse();
const { module, exportNames } = cjsPreparseModuleExports(filename);
Expand Down Expand Up @@ -290,7 +289,7 @@ translators.set('json', async function jsonStrategy(url, source) {
let module;
if (pathname) {
modulePath = isWindows ?
StringPrototypeReplace(pathname, winSepRegEx, '\\') : pathname;
StringPrototypeReplaceAll(pathname, '/', '\\') : pathname;
module = CJSModule._cache[modulePath];
if (module && module.loaded) {
const exports = module.exports;
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/policy/manifest.js
Expand Up @@ -10,11 +10,11 @@ const {
ObjectKeys,
ObjectSetPrototypeOf,
RegExpPrototypeExec,
RegExpPrototypeSymbolReplace,
RegExpPrototypeTest,
SafeMap,
SafeSet,
StringPrototypeEndsWith,
StringPrototypeReplace,
Symbol,
uncurryThis,
} = primordials;
Expand Down Expand Up @@ -651,10 +651,10 @@ const emptyOrProtocolOrResolve = (resourceHREF, base) => {
if (resourceHREF === '') return '';
if (StringPrototypeEndsWith(resourceHREF, ':')) {
// URL parse will trim these anyway, save the compute
resourceHREF = StringPrototypeReplace(
resourceHREF,
resourceHREF = RegExpPrototypeSymbolReplace(
// eslint-disable-next-line
/^[\x00-\x1F\x20]|\x09\x0A\x0D|[\x00-\x1F\x20]$/g,
resourceHREF,
''
);
if (RegExpPrototypeTest(/^[a-zA-Z][a-zA-Z+\-.]*:$/, resourceHREF)) {
Expand Down