Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
node-stream-zip
Advanced tools
The node-stream-zip npm package is a library designed for node.js that allows for efficient, stream-based operations on ZIP archives. It enables reading entries, extracting files, and navigating through the structure of ZIP files without needing to decompress the entire archive upfront. This makes it particularly useful for applications that need to work with large ZIP files or require selective access to archive contents.
Opening and reading ZIP archive
This code demonstrates how to open a ZIP file and read the number of entries (files and directories) it contains using the node-stream-zip package. It utilizes the async API for non-blocking operations.
const StreamZip = require('node-stream-zip');
const zip = new StreamZip.async({ file: './path/to/zipfile.zip' });
async function readZip() {
const entriesCount = await zip.entriesCount;
console.log(`Entries read: ${entriesCount}`);
await zip.close();
}
readZip();
Extracting a file from ZIP archive
This example shows how to extract a specific file from a ZIP archive to a desired location on the filesystem. It highlights the package's capability to handle individual file extraction efficiently.
const StreamZip = require('node-stream-zip');
const zip = new StreamZip.async({ file: './path/to/zipfile.zip' });
async function extractFile() {
await zip.extract('path/inside/zip.txt', './output/path/extracted.txt');
console.log('File extracted');
await zip.close();
}
extractFile();
Listing all entries in ZIP archive
This snippet is an example of how to list all entries (files and directories) in a ZIP archive. It demonstrates the package's ability to navigate and read the archive's structure.
const StreamZip = require('node-stream-zip');
const zip = new StreamZip.async({ file: './path/to/zipfile.zip' });
async function listEntries() {
const entries = await zip.entries();
for (const entry of Object.values(entries)) {
console.log(entry.name);
}
await zip.close();
}
listEntries();
adm-zip is a JavaScript implementation for zip data compression for NodeJS. It provides functionalities similar to node-stream-zip, such as reading and extracting zip files. However, adm-zip does not focus as much on stream-based operations, which can make it less efficient for large files or selective extraction scenarios.
jszip is another popular library for creating, reading, and editing .zip files with JavaScript, both in node environments and in the browser. Unlike node-stream-zip, jszip offers broader compatibility with web applications but might not offer the same level of efficiency for node.js specific stream-based operations.
yauzl is a minimalistic zip archive reader for Node.js, focusing on low memory usage. It is similar to node-stream-zip in its emphasis on non-blocking, stream-based operations for reading zip files. However, yauzl has a more minimalistic API and might require more manual handling for certain tasks compared to node-stream-zip.
node.js library for reading and extraction of ZIP archives.
Features:
npm i node-stream-zip
There are two APIs provided:
It's recommended to use the new, promise API, however the legacy callback API may be more flexible for certain operations.
Open a zip file
const StreamZip = require('node-stream-zip');
const zip = new StreamZip.async({ file: 'archive.zip' });
Stream one entry to stdout
const stm = await zip.stream('path/inside/zip.txt');
stm.pipe(process.stdout);
stm.on('end', () => zip.close());
Read a file as buffer
const data = await zip.entryData('path/inside/zip.txt');
await zip.close();
Extract one file to disk
await zip.extract('path/inside/zip.txt', './extracted.txt');
await zip.close();
List entries
const entriesCount = await zip.entriesCount;
console.log(`Entries read: ${entriesCount}`);
const entries = await zip.entries();
for (const entry of Object.values(entries)) {
const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;
console.log(`Entry ${entry.name}: ${desc}`);
}
// Do not forget to close the file once you're done
await zip.close();
Extract a folder from archive to disk
fs.mkdirSync('extracted');
await zip.extract('path/inside/zip/', './extracted');
await zip.close();
Extract everything
fs.mkdirSync('extracted');
const count = await zip.extract(null, './extracted');
console.log(`Extracted ${count} entries`);
await zip.close();
When extracting a folder, you can listen to extract
event
zip.on('extract', (entry, file) => {
console.log(`Extracted ${entry.name} to ${file}`);
});
entry
event is generated for every entry during loading
zip.on('entry', entry => {
// you can already stream this entry,
// without waiting until all entry descriptions are read (suitable for very large archives)
console.log(`Read entry ${entry.name}`);
});
Open a zip file
const StreamZip = require('node-stream-zip');
const zip = new StreamZip({ file: 'archive.zip' });
// Handle errors
zip.on('error', err => { /*...*/ });
List entries
zip.on('ready', () => {
console.log('Entries read: ' + zip.entriesCount);
for (const entry of Object.values(zip.entries())) {
const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;
console.log(`Entry ${entry.name}: ${desc}`);
}
// Do not forget to close the file once you're done
zip.close();
});
Stream one entry to stdout
zip.on('ready', () => {
zip.stream('path/inside/zip.txt', (err, stm) => {
stm.pipe(process.stdout);
stm.on('end', () => zip.close());
});
});
Extract one file to disk
zip.on('ready', () => {
zip.extract('path/inside/zip.txt', './extracted.txt', err => {
console.log(err ? 'Extract error' : 'Extracted');
zip.close();
});
});
Extract a folder from archive to disk
zip.on('ready', () => {
fs.mkdirSync('extracted');
zip.extract('path/inside/zip/', './extracted', err => {
console.log(err ? 'Extract error' : 'Extracted');
zip.close();
});
});
Extract everything
zip.on('ready', () => {
fs.mkdirSync('extracted');
zip.extract(null, './extracted', (err, count) => {
console.log(err ? 'Extract error' : `Extracted ${count} entries`);
zip.close();
});
});
Read a file as buffer in sync way
zip.on('ready', () => {
const data = zip.entryDataSync('path/inside/zip.txt');
zip.close();
});
When extracting a folder, you can listen to extract
event
zip.on('extract', (entry, file) => {
console.log(`Extracted ${entry.name} to ${file}`);
});
entry
event is generated for every entry during loading
zip.on('entry', entry => {
// you can already stream this entry,
// without waiting until all entry descriptions are read (suitable for very large archives)
console.log(`Read entry ${entry.name}`);
});
You can pass these options to the constructor
storeEntries: true
- you will be able to work with entries inside zip archive, otherwise the only way to access them is entry
eventskipEntryNameValidation: true
- by default, entry name is checked for malicious characters, like ../
or c:\123
, pass this flag to disable validation errorszip.entries()
- get all entries descriptionzip.entry(name)
- get entry description by namezip.stream(entry, function(err, stm) { })
- get entry data reader streamzip.entryDataSync(entry)
- get entry data in sync wayzip.close()
- cleanup after all entries have been read, streamed, extracted, and you don't need the archiveThe project doesn't require building. To run unit tests with nodeunit:
npm test
ZIP parsing code has been partially forked from cthackers/adm-zip (MIT license).
FAQs
node.js library for reading and extraction of ZIP archives
The npm package node-stream-zip receives a total of 1,413,858 weekly downloads. As such, node-stream-zip popularity was classified as popular.
We found that node-stream-zip demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.