Socket
Socket
Sign inDemoInstall

unzip-stream

Package Overview
Dependencies
6
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.2.1 to 0.2.2

test.js

6

lib/parser-stream.js

@@ -7,3 +7,3 @@ var Transform = require('stream').Transform;

if (!(this instanceof ParserStream)) {
return new ParserStream();
return new ParserStream(opts);
}

@@ -15,3 +15,3 @@

this.opts = opts || {};
this.unzipStream = new UnzipStream();
this.unzipStream = new UnzipStream(this.opts);

@@ -53,2 +53,2 @@ var self = this;

module.exports = ParserStream;
module.exports = ParserStream;

@@ -9,12 +9,13 @@ var binary = require('binary');

const states = {
START: 0,
LOCAL_FILE_HEADER: 1,
LOCAL_FILE_HEADER_SUFFIX: 2,
FILE_DATA: 3,
FILE_DATA_END: 4,
DATA_DESCRIPTOR: 5,
CENTRAL_DIRECTORY_FILE_HEADER: 6,
CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX: 7,
CENTRAL_DIRECTORY_END: 8,
CENTRAL_DIRECTORY_END_COMMENT: 9,
STREAM_START: 0,
START: 1,
LOCAL_FILE_HEADER: 2,
LOCAL_FILE_HEADER_SUFFIX: 3,
FILE_DATA: 4,
FILE_DATA_END: 5,
DATA_DESCRIPTOR: 6,
CENTRAL_DIRECTORY_FILE_HEADER: 7,
CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX: 8,
CENTRAL_DIRECTORY_END: 9,
CENTRAL_DIRECTORY_END_COMMENT: 10,

@@ -31,5 +32,5 @@ ERROR: 99

function UnzipStream() {
function UnzipStream(options) {
if (!(this instanceof UnzipStream)) {
return new UnzipStream();
return new UnzipStream(options);
}

@@ -39,4 +40,5 @@

this.options = options || {};
this.data = new Buffer('');
this.state = states.START;
this.state = states.STREAM_START;
this.parsedEntity = null;

@@ -52,2 +54,3 @@ this.outStreamInfo = {};

switch (this.state) {
case states.STREAM_START:
case states.START:

@@ -88,2 +91,3 @@ requiredLength = 4;

switch (this.state) {
case states.STREAM_START:
case states.START:

@@ -101,4 +105,12 @@ switch (chunk.readUInt32LE(0)) {

default:
var isStreamStart = this.state === states.STREAM_START;
this.state = states.ERROR;
this.emit("error", new Error("Invalid signature in zip file"));
var errMsg = isStreamStart ? "Not a valid zip file" : "Invalid signature in zip file";
if (this.options.debug) {
var sig = chunk.readUInt32LE(0);
var asString;
try { asString = chunk.slice(0, 4).toString(); } catch (e) {}
console.log("Unexpected signature in zip file: 0x" + sig.toString(16), '"' + asString + '"');
}
this.emit("error", new Error(errMsg));
return chunk.length;

@@ -116,4 +128,19 @@ }

var entry = new Entry();
entry.path = chunk.slice(0, this.parsedEntity.fileNameLength).toString();
this.parsedEntity.extra = this._readExtraFields(chunk.slice(this.parsedEntity.fileNameLength, this.parsedEntity.fileNameLength + this.parsedEntity.extraFieldLength));
var isUtf8 = (this.parsedEntity.flags & 0x800) !== 0;
entry.path = this._decodeString(chunk.slice(0, this.parsedEntity.fileNameLength), isUtf8);
var extraDataBuffer = chunk.slice(this.parsedEntity.fileNameLength, this.parsedEntity.fileNameLength + this.parsedEntity.extraFieldLength);
var extra = this._readExtraFields(extraDataBuffer);
if (extra && extra.parsed && extra.parsed.path && !isUtf8) {
entry.path = extra.parsed.path;
}
this.parsedEntity.extra = extra.parsed;
if (this.options.debug) {
const debugObj = Object.assign({}, this.parsedEntity, {
path: entry.path,
flags: '0x' + this.parsedEntity.flags.toString(16),
extraFields: extra && extra.debug
});
console.log("decoded local file entry:", JSON.stringify(debugObj, null, 2));
}
this._prepareOutStream(this.parsedEntity, entry);

@@ -135,2 +162,28 @@

// got file name in chunk[0..]
var isUtf8 = (this.parsedEntity.flags & 0x800) !== 0;
var path = this._decodeString(chunk.slice(0, this.parsedEntity.fileNameLength), isUtf8);
var extraDataBuffer = chunk.slice(this.parsedEntity.fileNameLength, this.parsedEntity.fileNameLength + this.parsedEntity.extraFieldLength);
var extra = this._readExtraFields(extraDataBuffer);
if (extra && extra.parsed && extra.parsed.path && !isUtf8) {
path = extra.parsed.path;
}
this.parsedEntity.extra = extra.parsed;
var isUnix = ((this.parsedEntity.versionMadeBy & 0xff00) >> 8) === 3;
var unixAttrs, isSymlink;
if (isUnix) {
unixAttrs = this.parsedEntity.externalFileAttributes >>> 16;
var fileType = unixAttrs >>> 12;
isSymlink = (fileType & 012) === 012; // __S_IFLNK
}
if (this.options.debug) {
const debugObj = Object.assign({}, this.parsedEntity, {
path: path,
flags: '0x' + this.parsedEntity.flags.toString(16),
unixAttrs: unixAttrs && '0' + unixAttrs.toString(8),
isSymlink: isSymlink,
extraFields: extra.debug,
});
console.log("decoded central directory file entry:", JSON.stringify(debugObj, null, 2));
}
this.state = states.START;

@@ -267,2 +320,6 @@

var extra = {};
var result = { parsed: extra };
if (this.options.debug) {
result.debug = [];
}
var index = 0;

@@ -278,4 +335,9 @@ while (index < data.length) {

var fieldType = undefined;
switch (vars.extraId) {
case 0x000a:
fieldType = "NTFS extra field";
break;
case 0x5455:
fieldType = "extended timestamp";
var timestampFields = data.readUInt8(index);

@@ -295,13 +357,107 @@ var offset = 1;

break;
case 0x7075:
fieldType = "Info-ZIP Unicode Path Extra Field";
var fieldVer = data.readUInt8(index);
if (fieldVer === 1) {
var offset = 1;
// TODO: should be checking this against our path buffer
var nameCrc32 = data.readUInt32LE(index + offset);
offset += 4;
var pathBuffer = data.slice(index + offset);
extra.path = pathBuffer.toString();
}
break;
case 0x000d:
case 0x5855:
fieldType = vars.extraId === 0x000d ? "PKWARE Unix" : "Info-ZIP UNIX (type 1)";
var offset = 0;
if (vars.extraSize >= 8) {
var atime = new Date(data.readUInt32LE(index + offset) * 1000);
offset += 4;
var mtime = new Date(data.readUInt32LE(index + offset) * 1000);
offset += 4;
extra.atime = atime;
extra.mtime = mtime;
if (vars.extraSize >= 12) {
var uid = data.readUInt16LE(index + offset);
offset += 2;
var gid = data.readUInt16LE(index + offset);
offset += 2;
extra.uid = uid;
extra.gid = gid;
}
}
break;
case 0x7855:
fieldType = "Info-ZIP UNIX (type 2)";
var offset = 0;
if (vars.extraSize >= 4) {
var uid = data.readUInt16LE(index + offset);
offset += 2;
var gid = data.readUInt16LE(index + offset);
offset += 2;
extra.uid = uid;
extra.gid = gid;
}
break;
case 0x7875:
/* TODO: handle
var uidSize = data.readUInt8(index + 1);
var gidSize = data.readUInt8(index + 1 + uidSize);
*/
fieldType = "Info-ZIP New Unix";
var offset = 0;
var extraVer = data.readUInt8(index);
offset += 1;
if (extraVer === 1) {
var uidSize = data.readUInt8(index + offset);
offset += 1;
if (uidSize <= 6) {
extra.uid = data.readUIntLE(index + offset, uidSize);
}
offset += uidSize;
var gidSize = data.readUInt8(index + offset);
offset += 1;
if (gidSize <= 6) {
extra.gid = data.readUIntLE(index + offset, gidSize);
}
}
break;
case 0x756e:
fieldType = "ASi Unix";
var offset = 0;
if (vars.extraSize >= 14) {
var crc = data.readUInt32LE(index + offset);
offset += 4;
var mode = data.readUInt16LE(index + offset);
offset += 2;
var sizdev = data.readUInt32LE(index + offset);
offset += 4;
var uid = data.readUInt16LE(index + offset);
offset += 2;
var gid = data.readUInt16LE(index + offset);
offset += 2;
extra.mode = mode;
extra.uid = uid;
extra.gid = gid;
if (vars.extraSize > 14) {
var start = index + offset;
var end = index + vars.extraSize - 14;
var symlinkName = this._decodeString(data.slice(start, end));
extra.symlink = symlinkName;
}
}
break;
}
if (this.options.debug) {
result.debug.push({
extraId: '0x' + vars.extraId.toString(16),
description: fieldType,
data: data.slice(index, index + vars.extraSize).inspect()
});
}
index += vars.extraSize;
}
return extra;
return result;
}

@@ -357,2 +513,19 @@

const cp437 = '\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ';
UnzipStream.prototype._decodeString = function (buffer, isUtf8) {
if (isUtf8) {
return buffer.toString('utf8');
}
// allow passing custom decoder
if (this.options.decodeString) {
return this.options.decodeString(buffer);
}
let result = "";
for (var i=0; i<buffer.length; i++) {
result += cp437[buffer[i]];
}
return result;
}
UnzipStream.prototype._parseOrOutput = function (encoding, cb) {

@@ -359,0 +532,0 @@ var consume;

{
"name": "unzip-stream",
"version": "0.2.1",
"version": "0.2.2",
"description": "Process zip files using streaming API",

@@ -5,0 +5,0 @@ "author": "Michal Hruby <michal.mhr@gmail.com>",

@@ -74,4 +74,11 @@ # unzip-stream

### Extra options
The `Parse` and `Extract` methods allow passing an object with `decodeString` property which will be used to decode non-utf8 file names in the archive. If not specified a fallback will be used.
```javascript
let parser = unzip.Parse({ decodeString: (buffer) => { return iconvLite.decode(buffer, 'iso-8859-2'); } });
input.pipe(parser).pipe(...);
```
### What's missing?
Currently only ZIP files up to version 2.1 are supported - which means no Zip64 support. There's also no support for encrypted (password protected) zips, or symlinks.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc