compressing 1.10.2 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -10
- package/lib/utils.js +55 -12
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
# compressing
|
|
1
|
+
# compressing@1
|
|
2
2
|
|
|
3
3
|
[![NPM version][npm-image]][npm-url]
|
|
4
4
|
[![Test coverage][codecov-image]][codecov-url]
|
|
5
5
|
[![npm download][download-image]][download-url]
|
|
6
|
+
[](https://nodejs.org/en/download/)
|
|
7
|
+
[](https://makeapullrequest.com)
|
|
8
|
+

|
|
6
9
|
|
|
7
10
|
[npm-image]: https://img.shields.io/npm/v/compressing.svg?style=flat-square
|
|
8
11
|
[npm-url]: https://npmjs.org/package/compressing
|
|
@@ -11,6 +14,10 @@
|
|
|
11
14
|
[download-image]: https://img.shields.io/npm/dm/compressing.svg?style=flat-square
|
|
12
15
|
[download-url]: https://npmjs.org/package/compressing
|
|
13
16
|
|
|
17
|
+
## ⚠️ Warning
|
|
18
|
+
|
|
19
|
+
**Version 1.x is no longer maintained. Please upgrade to version 2.x as soon as possible.**
|
|
20
|
+
|
|
14
21
|
The missing compressing and uncompressing lib for node.
|
|
15
22
|
|
|
16
23
|
Currently supported:
|
|
@@ -23,7 +30,7 @@ Currently supported:
|
|
|
23
30
|
## Install
|
|
24
31
|
|
|
25
32
|
```bash
|
|
26
|
-
npm install compressing
|
|
33
|
+
npm install compressing@1
|
|
27
34
|
```
|
|
28
35
|
|
|
29
36
|
## Usage
|
|
@@ -364,15 +371,9 @@ Due to the design of the .zip file format, it's impossible to interpret a .zip f
|
|
|
364
371
|
Although the API is streaming style(try to keep it handy), it still loads all data into memory.
|
|
365
372
|
|
|
366
373
|
<https://github.com/thejoshwolfe/yauzl#no-streaming-unzip-api>
|
|
367
|
-
<!-- GITCONTRIBUTOR_START -->
|
|
368
374
|
|
|
369
375
|
## Contributors
|
|
370
376
|
|
|
371
|
-
|
|
372
|
-
| :---: | :---: | :---: | :---: | :---: | :---: |
|
|
373
|
-
|[<img src="https://avatars.githubusercontent.com/u/13938334?v=4" width="100px;"/><br/><sub><b>bytemain</b></sub>](https://github.com/bytemain)<br/>|[<img src="https://avatars.githubusercontent.com/u/20432815?v=4" width="100px;"/><br/><sub><b>rickyes</b></sub>](https://github.com/rickyes)<br/>|[<img src="https://avatars.githubusercontent.com/u/8382136?v=4" width="100px;"/><br/><sub><b>Ryqsky</b></sub>](https://github.com/Ryqsky)<br/>|[<img src="https://avatars.githubusercontent.com/u/47357585?v=4" width="100px;"/><br/><sub><b>songhn233</b></sub>](https://github.com/songhn233)<br/>|[<img src="https://avatars.githubusercontent.com/u/160386?v=4" width="100px;"/><br/><sub><b>Infiltrator</b></sub>](https://github.com/Infiltrator)<br/>|[<img src="https://avatars.githubusercontent.com/u/13861843?v=4" width="100px;"/><br/><sub><b>ZeekoZhu</b></sub>](https://github.com/ZeekoZhu)<br/>|
|
|
374
|
-
[<img src="https://avatars.githubusercontent.com/u/6897780?v=4" width="100px;"/><br/><sub><b>killagu</b></sub>](https://github.com/killagu)<br/>|[<img src="https://avatars.githubusercontent.com/u/59508678?v=4" width="100px;"/><br/><sub><b>okaponta</b></sub>](https://github.com/okaponta)<br/>|[<img src="https://avatars.githubusercontent.com/u/9857273?v=4" width="100px;"/><br/><sub><b>ShadyZOZ</b></sub>](https://github.com/ShadyZOZ)<br/>
|
|
375
|
-
|
|
376
|
-
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Thu Aug 03 2023 01:39:37 GMT+0800`.
|
|
377
|
+
[](https://github.com/node-modules/compressing/graphs/contributors)
|
|
377
378
|
|
|
378
|
-
|
|
379
|
+
Made with [contributors-img](https://contrib.rocks).
|
package/lib/utils.js
CHANGED
|
@@ -5,6 +5,22 @@ const path = require('path');
|
|
|
5
5
|
const mkdirp = require('mkdirp');
|
|
6
6
|
const pump = require('pump');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Check if childPath is within parentPath (prevents path traversal attacks)
|
|
10
|
+
* @param {string} childPath - The path to check
|
|
11
|
+
* @param {string} parentPath - The parent directory path
|
|
12
|
+
* @returns {boolean} - True if childPath is within parentPath
|
|
13
|
+
*/
|
|
14
|
+
function isPathWithinParent(childPath, parentPath) {
|
|
15
|
+
const normalizedChild = path.resolve(childPath);
|
|
16
|
+
const normalizedParent = path.resolve(parentPath);
|
|
17
|
+
const parentWithSep = normalizedParent.endsWith(path.sep)
|
|
18
|
+
? normalizedParent
|
|
19
|
+
: normalizedParent + path.sep;
|
|
20
|
+
return normalizedChild === normalizedParent ||
|
|
21
|
+
normalizedChild.startsWith(parentWithSep);
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
// file/fileBuffer/stream
|
|
9
25
|
exports.sourceType = source => {
|
|
10
26
|
if (!source) return undefined;
|
|
@@ -93,6 +109,9 @@ exports.makeUncompressFn = StreamClass => {
|
|
|
93
109
|
mkdirp(destDir, err => {
|
|
94
110
|
if (err) return reject(err);
|
|
95
111
|
|
|
112
|
+
// Resolve destDir to absolute path for security validation
|
|
113
|
+
const resolvedDestDir = path.resolve(destDir);
|
|
114
|
+
|
|
96
115
|
let entryCount = 0;
|
|
97
116
|
let successCount = 0;
|
|
98
117
|
let isFinish = false;
|
|
@@ -109,31 +128,53 @@ exports.makeUncompressFn = StreamClass => {
|
|
|
109
128
|
.on('error', reject)
|
|
110
129
|
.on('entry', (header, stream, next) => {
|
|
111
130
|
stream.on('end', next);
|
|
131
|
+
const destFilePath = path.join(resolvedDestDir, header.name);
|
|
132
|
+
const resolvedDestPath = path.resolve(destFilePath);
|
|
133
|
+
|
|
134
|
+
// Security: Validate that the entry path doesn't escape the destination directory
|
|
135
|
+
if (!isPathWithinParent(resolvedDestPath, resolvedDestDir)) {
|
|
136
|
+
console.warn(`[compressing] Skipping entry with path traversal: "${header.name}" -> "${resolvedDestPath}"`);
|
|
137
|
+
stream.resume();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
112
140
|
|
|
113
141
|
if (header.type === 'file') {
|
|
114
|
-
const
|
|
115
|
-
mkdirp(
|
|
142
|
+
const dir = path.dirname(destFilePath);
|
|
143
|
+
mkdirp(dir, err => {
|
|
116
144
|
if (err) return reject(err);
|
|
117
145
|
|
|
118
146
|
entryCount++;
|
|
119
|
-
pump(stream, fs.createWriteStream(
|
|
147
|
+
pump(stream, fs.createWriteStream(destFilePath, { mode: opts.mode || header.mode }), err => {
|
|
120
148
|
if (err) return reject(err);
|
|
121
149
|
successCount++;
|
|
122
150
|
done();
|
|
123
151
|
});
|
|
124
152
|
});
|
|
125
153
|
} else if (header.type === 'symlink') {
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
154
|
+
const dir = path.dirname(destFilePath);
|
|
155
|
+
const target = path.resolve(dir, header.linkname);
|
|
156
|
+
|
|
157
|
+
// Security: Validate that the symlink target doesn't escape the destination directory
|
|
158
|
+
if (!isPathWithinParent(target, resolvedDestDir)) {
|
|
159
|
+
console.warn(`[compressing] Skipping symlink "${header.name}": target "${target}" escapes extraction directory`);
|
|
160
|
+
stream.resume();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
129
164
|
entryCount++;
|
|
130
|
-
|
|
165
|
+
|
|
166
|
+
mkdirp(dir, err => {
|
|
131
167
|
if (err) return reject(err);
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
|
|
169
|
+
const relativeTarget = path.relative(dir, target);
|
|
170
|
+
fs.symlink(relativeTarget, destFilePath, err => {
|
|
171
|
+
if (err) return reject(err);
|
|
172
|
+
successCount++;
|
|
173
|
+
stream.resume();
|
|
174
|
+
});
|
|
134
175
|
});
|
|
135
176
|
} else { // directory
|
|
136
|
-
mkdirp(
|
|
177
|
+
mkdirp(destFilePath, err => {
|
|
137
178
|
if (err) return reject(err);
|
|
138
179
|
stream.resume();
|
|
139
180
|
});
|
|
@@ -175,7 +216,7 @@ function normalizePath(fileName) {
|
|
|
175
216
|
return fileName;
|
|
176
217
|
}
|
|
177
218
|
|
|
178
|
-
|
|
219
|
+
function stripFileName(strip, fileName, type) {
|
|
179
220
|
// before
|
|
180
221
|
// node/package.json
|
|
181
222
|
// node/lib/index.js
|
|
@@ -218,4 +259,6 @@ exports.stripFileName = (strip, fileName, type) => {
|
|
|
218
259
|
|
|
219
260
|
strip = Math.min(strip, s.length - 1);
|
|
220
261
|
return s.slice(strip).join('/') || '/';
|
|
221
|
-
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
exports.stripFileName = stripFileName;
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compressing",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.4",
|
|
4
4
|
"description": "Everything you need for compressing and uncompressing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"contributor": "git-contributor",
|
|
8
7
|
"test:ts": "tsc -p ./test/fixtures/types/tsconfig.json",
|
|
9
8
|
"test:js": "egg-bin test --ts false",
|
|
10
9
|
"test": "npm run test:js && npm run test:ts",
|
|
@@ -57,7 +56,6 @@
|
|
|
57
56
|
"egg-bin": "6",
|
|
58
57
|
"eslint": "8",
|
|
59
58
|
"eslint-config-egg": "12",
|
|
60
|
-
"git-contributor": "2",
|
|
61
59
|
"mm": "^2.0.0",
|
|
62
60
|
"mz-modules": "^2.1.0",
|
|
63
61
|
"typescript": "5",
|