Skip to content

Commit 19d2d66

Browse files
targosjasnell
authored andcommitted
path: fix normalize paths ending with two dots
Fixes: nodejs-private/security#147 PR-URL: nodejs-private/node-private#94 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Doug Wilson <[email protected]> Reviewed-By: Myles Borins <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent 0a050e9 commit 19d2d66

File tree

2 files changed

+27
-16
lines changed

2 files changed

+27
-16
lines changed

lib/path.js

+20-16
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ function assertPath(path) {
3232
// Resolves . and .. elements in a path with directory names
3333
function normalizeStringWin32(path, allowAboveRoot) {
3434
var res = '';
35+
var lastSegmentLength = 0;
3536
var lastSlash = -1;
3637
var dots = 0;
3738
var code;
38-
var isAboveRoot = false;
3939
for (var i = 0; i <= path.length; ++i) {
4040
if (i < path.length)
4141
code = path.charCodeAt(i);
@@ -47,7 +47,7 @@ function normalizeStringWin32(path, allowAboveRoot) {
4747
if (lastSlash === i - 1 || dots === 1) {
4848
// NOOP
4949
} else if (lastSlash !== i - 1 && dots === 2) {
50-
if (res.length < 2 || !isAboveRoot ||
50+
if (res.length < 2 || lastSegmentLength !== 2 ||
5151
res.charCodeAt(res.length - 1) !== 46/*.*/ ||
5252
res.charCodeAt(res.length - 2) !== 46/*.*/) {
5353
if (res.length > 2) {
@@ -58,20 +58,22 @@ function normalizeStringWin32(path, allowAboveRoot) {
5858
break;
5959
}
6060
if (j !== start) {
61-
if (j === -1)
61+
if (j === -1) {
6262
res = '';
63-
else
63+
lastSegmentLength = 0;
64+
} else {
6465
res = res.slice(0, j);
66+
lastSegmentLength = j;
67+
}
6568
lastSlash = i;
6669
dots = 0;
67-
isAboveRoot = false;
6870
continue;
6971
}
7072
} else if (res.length === 2 || res.length === 1) {
7173
res = '';
74+
lastSegmentLength = 0;
7275
lastSlash = i;
7376
dots = 0;
74-
isAboveRoot = false;
7577
continue;
7678
}
7779
}
@@ -80,14 +82,14 @@ function normalizeStringWin32(path, allowAboveRoot) {
8082
res += '\\..';
8183
else
8284
res = '..';
83-
isAboveRoot = true;
85+
lastSegmentLength = 2;
8486
}
8587
} else {
8688
if (res.length > 0)
8789
res += '\\' + path.slice(lastSlash + 1, i);
8890
else
8991
res = path.slice(lastSlash + 1, i);
90-
isAboveRoot = false;
92+
lastSegmentLength = i - lastSlash - 1;
9193
}
9294
lastSlash = i;
9395
dots = 0;
@@ -103,10 +105,10 @@ function normalizeStringWin32(path, allowAboveRoot) {
103105
// Resolves . and .. elements in a path with directory names
104106
function normalizeStringPosix(path, allowAboveRoot) {
105107
var res = '';
108+
var lastSegmentLength = 0;
106109
var lastSlash = -1;
107110
var dots = 0;
108111
var code;
109-
var isAboveRoot = false;
110112
for (var i = 0; i <= path.length; ++i) {
111113
if (i < path.length)
112114
code = path.charCodeAt(i);
@@ -118,7 +120,7 @@ function normalizeStringPosix(path, allowAboveRoot) {
118120
if (lastSlash === i - 1 || dots === 1) {
119121
// NOOP
120122
} else if (lastSlash !== i - 1 && dots === 2) {
121-
if (res.length < 2 || !isAboveRoot ||
123+
if (res.length < 2 || lastSegmentLength !== 2 ||
122124
res.charCodeAt(res.length - 1) !== 46/*.*/ ||
123125
res.charCodeAt(res.length - 2) !== 46/*.*/) {
124126
if (res.length > 2) {
@@ -129,20 +131,22 @@ function normalizeStringPosix(path, allowAboveRoot) {
129131
break;
130132
}
131133
if (j !== start) {
132-
if (j === -1)
134+
if (j === -1) {
133135
res = '';
134-
else
136+
lastSegmentLength = 0;
137+
} else {
135138
res = res.slice(0, j);
139+
lastSegmentLength = j;
140+
}
136141
lastSlash = i;
137142
dots = 0;
138-
isAboveRoot = false;
139143
continue;
140144
}
141145
} else if (res.length === 2 || res.length === 1) {
142146
res = '';
147+
lastSegmentLength = 0;
143148
lastSlash = i;
144149
dots = 0;
145-
isAboveRoot = false;
146150
continue;
147151
}
148152
}
@@ -151,14 +155,14 @@ function normalizeStringPosix(path, allowAboveRoot) {
151155
res += '/..';
152156
else
153157
res = '..';
154-
isAboveRoot = true;
158+
lastSegmentLength = 2;
155159
}
156160
} else {
157161
if (res.length > 0)
158162
res += '/' + path.slice(lastSlash + 1, i);
159163
else
160164
res = path.slice(lastSlash + 1, i);
161-
isAboveRoot = false;
165+
lastSegmentLength = i - lastSlash - 1;
162166
}
163167
lastSlash = i;
164168
dots = 0;

test/parallel/test-path-normalize.js

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar');
2323
assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz');
2424
assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\');
2525
assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..');
26+
assert.strictEqual(path.win32.normalize('..\\foo..\\..\\..\\bar'),
27+
'..\\..\\bar');
28+
assert.strictEqual(path.win32.normalize('..\\...\\..\\.\\...\\..\\..\\bar'),
29+
'..\\..\\bar');
2630

2731
assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'),
2832
'fixtures/b/c.js');
@@ -37,3 +41,6 @@ assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');
3741
assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz');
3842
assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../');
3943
assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..');
44+
assert.strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar');
45+
assert.strictEqual(path.posix.normalize('../.../.././.../../../bar'),
46+
'../../bar');

0 commit comments

Comments
 (0)