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.
Files changed (3) hide show
  1. package/README.md +11 -10
  2. package/lib/utils.js +55 -12
  3. 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
+ [![Node.js Version](https://img.shields.io/node/v/compressing.svg?style=flat)](https://nodejs.org/en/download/)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
8
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/node-modules/compressing)
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
- |[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/456108?v=4" width="100px;"/><br/><sub><b>shaoshuai0102</b></sub>](https://github.com/shaoshuai0102)<br/>|[<img src="https://avatars.githubusercontent.com/u/360661?v=4" width="100px;"/><br/><sub><b>popomore</b></sub>](https://github.com/popomore)<br/>|[<img src="https://avatars.githubusercontent.com/u/32174276?v=4" width="100px;"/><br/><sub><b>semantic-release-bot</b></sub>](https://github.com/semantic-release-bot)<br/>|[<img src="https://avatars.githubusercontent.com/u/9692408?v=4" width="100px;"/><br/><sub><b>DiamondYuan</b></sub>](https://github.com/DiamondYuan)<br/>|[<img src="https://avatars.githubusercontent.com/u/101238421?v=4" width="100px;"/><br/><sub><b>acyza</b></sub>](https://github.com/acyza)<br/>|
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
+ [![Contributors](https://contrib.rocks/image?repo=node-modules/compressing)](https://github.com/node-modules/compressing/graphs/contributors)
377
378
 
378
- <!-- GITCONTRIBUTOR_END -->
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 fullpath = path.join(destDir, header.name);
115
- mkdirp(path.dirname(fullpath), err => {
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(fullpath, { mode: opts.mode || header.mode }), err => {
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
- // symlink
127
- const src = path.join(destDir, header.name);
128
- const target = path.resolve(path.dirname(src), header.linkname);
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
- fs.symlink(target, src, err => {
165
+
166
+ mkdirp(dir, err => {
131
167
  if (err) return reject(err);
132
- successCount++;
133
- stream.resume();
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(path.join(destDir, header.name), err => {
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
- exports.stripFileName = (strip, fileName, type) => {
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.2",
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",