Comparing version 2.6.0 to 2.7.0
100
index.js
@@ -16,2 +16,3 @@ var fs = require("fs"); | ||
exports.dosDateTimeToDate = dosDateTimeToDate; | ||
exports.validateFileName = validateFileName; | ||
exports.ZipFile = ZipFile; | ||
@@ -29,2 +30,3 @@ exports.Entry = Entry; | ||
if (options.lazyEntries == null) options.lazyEntries = false; | ||
if (options.decodeStrings == null) options.decodeStrings = true; | ||
if (callback == null) callback = defaultCallback; | ||
@@ -48,2 +50,3 @@ fs.open(path, "r", function(err, fd) { | ||
if (options.lazyEntries == null) options.lazyEntries = false; | ||
if (options.decodeStrings == null) options.decodeStrings = true; | ||
if (callback == null) callback = defaultCallback; | ||
@@ -65,2 +68,3 @@ fs.fstat(fd, function(err, stats) { | ||
if (options.lazyEntries == null) options.lazyEntries = false; | ||
if (options.decodeStrings == null) options.decodeStrings = true; | ||
// i got your open file right here. | ||
@@ -79,2 +83,4 @@ var reader = fd_slicer.createFromBuffer(buffer); | ||
if (options.lazyEntries == null) options.lazyEntries = false; | ||
if (options.decodeStrings == null) options.decodeStrings = true; | ||
var decodeStrings = !!options.decodeStrings; | ||
if (callback == null) callback = defaultCallback; | ||
@@ -128,6 +134,7 @@ if (typeof totalSize !== "number") throw new Error("expected totalSize parameter to be a number"); | ||
// the encoding is always cp437. | ||
var comment = bufferToString(eocdrBuffer, 22, eocdrBuffer.length, false); | ||
var comment = decodeStrings ? decodeBuffer(eocdrBuffer, 22, eocdrBuffer.length, false) | ||
: eocdrBuffer.slice(22); | ||
if (!(entryCount === 0xffff || centralDirectoryOffset === 0xffffffff)) { | ||
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries)); | ||
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries, decodeStrings)); | ||
} | ||
@@ -173,3 +180,3 @@ | ||
// 56 - zip64 extensible data sector (variable size) | ||
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries)); | ||
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries, decodeStrings)); | ||
}); | ||
@@ -184,3 +191,3 @@ }); | ||
util.inherits(ZipFile, EventEmitter); | ||
function ZipFile(reader, centralDirectoryOffset, fileSize, entryCount, comment, autoClose, lazyEntries) { | ||
function ZipFile(reader, centralDirectoryOffset, fileSize, entryCount, comment, autoClose, lazyEntries, decodeStrings) { | ||
var self = this; | ||
@@ -204,2 +211,3 @@ EventEmitter.call(self); | ||
self.lazyEntries = !!lazyEntries; | ||
self.decodeStrings = !!decodeStrings; | ||
self.isOpen = true; | ||
@@ -285,4 +293,5 @@ self.emittedError = false; | ||
// 46 - File name | ||
var isUtf8 = entry.generalPurposeBitFlag & 0x800 | ||
entry.fileName = bufferToString(buffer, 0, entry.fileNameLength, isUtf8); | ||
var isUtf8 = (entry.generalPurposeBitFlag & 0x800) !== 0; | ||
entry.fileName = self.decodeStrings ? decodeBuffer(buffer, 0, entry.fileNameLength, isUtf8) | ||
: buffer.slice(0, entry.fileNameLength); | ||
@@ -310,3 +319,6 @@ // 46+n - Extra field | ||
// 46+n+m - File comment | ||
entry.fileComment = bufferToString(buffer, fileCommentStart, fileCommentStart + entry.fileCommentLength, isUtf8); | ||
entry.fileComment = self.decodeStrings ? decodeBuffer(buffer, fileCommentStart, fileCommentStart + entry.fileCommentLength, isUtf8) | ||
: buffer.slice(fileCommentStart, fileCommentStart + entry.fileCommentLength); | ||
// compatibility hack for https://github.com/thejoshwolfe/yauzl/issues/47 | ||
entry.comment = entry.fileComment; | ||
@@ -362,25 +374,27 @@ self.readEntryCursor += buffer.length; | ||
// see https://github.com/thejoshwolfe/yauzl/issues/33 | ||
for (var i = 0; i < entry.extraFields.length; i++) { | ||
var extraField = entry.extraFields[i]; | ||
if (extraField.id === 0x7075) { | ||
if (extraField.data.length < 6) { | ||
// too short to be meaningful | ||
continue; | ||
if (self.decodeStrings) { | ||
for (var i = 0; i < entry.extraFields.length; i++) { | ||
var extraField = entry.extraFields[i]; | ||
if (extraField.id === 0x7075) { | ||
if (extraField.data.length < 6) { | ||
// too short to be meaningful | ||
continue; | ||
} | ||
// Version 1 byte version of this extra field, currently 1 | ||
if (extraField.data.readUInt8(0) !== 1) { | ||
// > Changes may not be backward compatible so this extra | ||
// > field should not be used if the version is not recognized. | ||
continue; | ||
} | ||
// NameCRC32 4 bytes File Name Field CRC32 Checksum | ||
var oldNameCrc32 = extraField.data.readUInt32LE(1); | ||
if (crc32.unsigned(buffer.slice(0, entry.fileNameLength)) !== oldNameCrc32) { | ||
// > If the CRC check fails, this UTF-8 Path Extra Field should be | ||
// > ignored and the File Name field in the header should be used instead. | ||
continue; | ||
} | ||
// UnicodeName Variable UTF-8 version of the entry File Name | ||
entry.fileName = decodeBuffer(extraField.data, 5, extraField.data.length, true); | ||
break; | ||
} | ||
// Version 1 byte version of this extra field, currently 1 | ||
if (extraField.data.readUInt8(0) !== 1) { | ||
// > Changes may not be backward compatible so this extra | ||
// > field should not be used if the version is not recognized. | ||
continue; | ||
} | ||
// NameCRC32 4 bytes File Name Field CRC32 Checksum | ||
var oldNameCrc32 = extraField.data.readUInt32LE(1); | ||
if (crc32.unsigned(buffer.slice(0, entry.fileNameLength)) !== oldNameCrc32) { | ||
// > If the CRC check fails, this UTF-8 Path Extra Field should be | ||
// > ignored and the File Name field in the header should be used instead. | ||
continue; | ||
} | ||
// UnicodeName Variable UTF-8 version of the entry File Name | ||
entry.fileName = bufferToString(extraField.data, 5, extraField.data.length, true); | ||
break; | ||
} | ||
@@ -397,12 +411,6 @@ } | ||
// validate file name | ||
if (entry.fileName.indexOf("\\") !== -1) { | ||
return emitErrorAndAutoClose(self, new Error("invalid characters in fileName: " + entry.fileName)); | ||
if (self.decodeStrings) { | ||
var errorMessage = validateFileName(entry.fileName); | ||
if (errorMessage != null) return emitErrorAndAutoClose(self, new Error(errorMessage)); | ||
} | ||
if (/^[a-zA-Z]:/.test(entry.fileName) || /^\//.test(entry.fileName)) { | ||
return emitErrorAndAutoClose(self, new Error("absolute path: " + entry.fileName)); | ||
} | ||
if (entry.fileName.split("/").indexOf("..") !== -1) { | ||
return emitErrorAndAutoClose(self, new Error("invalid relative path: " + entry.fileName)); | ||
} | ||
self.emit("entry", entry); | ||
@@ -520,2 +528,16 @@ | ||
function validateFileName(fileName) { | ||
if (fileName.indexOf("\\") !== -1) { | ||
return "invalid characters in fileName: " + fileName; | ||
} | ||
if (/^[a-zA-Z]:/.test(fileName) || /^\//.test(fileName)) { | ||
return "absolute path: " + fileName; | ||
} | ||
if (fileName.split("/").indexOf("..") !== -1) { | ||
return "invalid relative path: " + fileName; | ||
} | ||
// all good | ||
return null; | ||
}; | ||
function readAndAssertNoEof(reader, buffer, offset, length, position, callback) { | ||
@@ -658,3 +680,3 @@ if (length === 0) { | ||
var cp437 = '\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ '; | ||
function bufferToString(buffer, start, end, isUtf8) { | ||
function decodeBuffer(buffer, start, end, isUtf8) { | ||
if (isUtf8) { | ||
@@ -661,0 +683,0 @@ return buffer.toString("utf8", start, end); |
{ | ||
"name": "yauzl", | ||
"version": "2.6.0", | ||
"version": "2.7.0", | ||
"description": "yet another unzip library for node", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -22,4 +22,3 @@ # yauzl | ||
* Catch unsafe file names. | ||
A zip file entry throws an error if its file name starts with `"/"` or `/[A-Za-z]:\//` | ||
or if it contains `".."` path segments or `"\\"` (per the spec). | ||
See `validateFileName()`. | ||
@@ -74,5 +73,5 @@ ## Usage | ||
Calls `fs.open(path, "r")` and gives the `fd`, `options`, and `callback` to `fromFd()` below. | ||
Calls `fs.open(path, "r")` and reads the `fd` effectively the same as `fromFd()` would. | ||
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false}`. | ||
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false, decodeStrings: true}`. | ||
@@ -95,2 +94,14 @@ `autoClose` is effectively equivalent to: | ||
`decodeStrings` is the default and causes yauzl to decode strings with `CP437` or `UTF-8` as required by the spec. | ||
The exact effects of turning this option off are: | ||
* `zipfile.comment`, `entry.fileName`, and `entry.fileComment` will be `Buffer` objects instead of `String`s. | ||
* Any Info-ZIP Unicode Path Extra Field will be ignored. See `extraFields`. | ||
* Automatic file name validation will not be performed. See `validateFileName()`. | ||
The `callback` is given the arguments `(err, zipfile)`. | ||
An `err` is provided if the End of Central Directory Record cannot be found, or if its metadata appears malformed. | ||
This kind of error usually indicates that this is not a zip file. | ||
Otherwise, `zipfile` is an instance of `ZipFile`. | ||
### fromFd(fd, [options], [callback]) | ||
@@ -102,9 +113,5 @@ | ||
The `callback` is given the arguments `(err, zipfile)`. | ||
An `err` is provided if the End of Central Directory Record Signature cannot be found in the file, | ||
which indicates that the fd is not a zip file. | ||
`zipfile` is an instance of `ZipFile`. | ||
`options` may be omitted or `null`. The defaults are `{autoClose: false, lazyEntries: false, decodeStrings: true}`. | ||
`options` may be omitted or `null`. The defaults are `{autoClose: false, lazyEntries: false}`. | ||
See `open()` for the meaning of the options. | ||
See `open()` for the meaning of the options and callback. | ||
@@ -115,3 +122,2 @@ ### fromBuffer(buffer, [options], [callback]) | ||
`buffer` is a `Buffer`. | ||
`callback` is effectively passed directly to `fromFd()`. | ||
@@ -122,4 +128,5 @@ If a `ZipFile` is acquired from this method, | ||
`options` may be omitted or `null`. The defaults are `{lazyEntries: false}`. | ||
See `open()` for the meaning of the options. | ||
`options` may be omitted or `null`. The defaults are `{lazyEntries: false, decodeStrings: true}`. | ||
See `open()` for the meaning of the options and callback. | ||
The `autoClose` option is ignored for this method. | ||
@@ -129,3 +136,3 @@ | ||
This method of creating a zip file allows clients to implement their own back-end file system. | ||
This method of reading a zip file allows clients to implement their own back-end file system. | ||
For example, a client might translate read calls into network requests. | ||
@@ -137,5 +144,6 @@ | ||
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false}`. | ||
See `open()` for the meaning of the options. | ||
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false, decodeStrings: true}`. | ||
See `open()` for the meaning of the options and callback. | ||
### dosDateTimeToDate(date, time) | ||
@@ -148,2 +156,16 @@ | ||
### validateFileName(fileName) | ||
Returns `null` or a `String` error message depending on the validity of `fileName`. | ||
If `fileName` starts with `"/"` or `/[A-Za-z]:\//` or if it contains `".."` path segments or `"\\"`, | ||
this function returns an error message appropriate for use like this: | ||
```js | ||
var errorMessage = yauzl.validateFileName(fileName); | ||
if (errorMessage != null) throw new Error(errorMessage); | ||
``` | ||
This function is automatically run for each entry, as long as `decodeStrings` is `true`. | ||
See `open()` and `Event: "entry"` for more information. | ||
### Class: ZipFile | ||
@@ -159,2 +181,5 @@ | ||
If `decodeStrings` is `true`, entries emitted via this event have already passed file name validation. | ||
See `validateFileName()` and `open()` for more information. | ||
#### Event: "end" | ||
@@ -253,2 +278,4 @@ | ||
If `decodeStrings` is `false` (see `open()`), this field is the undecoded `Buffer` instead of a decoded `String`. | ||
### Class: Entry | ||
@@ -285,5 +312,9 @@ | ||
If `fileName` would contain unsafe characters, such as an absolute path or | ||
a relative directory, yauzl emits an error instead of an entry. | ||
This field is automatically validated by `validateFileName()` before yauzl emits an "entry" event. | ||
If this field would contain unsafe characters, yauzl emits an error instead of an entry. | ||
If `decodeStrings` is `false` (see `open()`), this field is the undecoded `Buffer` instead of a decoded `String`. | ||
Therefore, `generalPurposeBitFlag` and any Info-ZIP Unicode Path Extra Field are ignored. | ||
Furthermore, no automatic file name validation is performed for this file name. | ||
#### extraFields | ||
@@ -303,2 +334,3 @@ | ||
and the file name in the central directory record for this entry is ignored. | ||
Note that when `decodeStrings` is false, all Info-ZIP Unicode Path Extra Fields are ignored. | ||
@@ -308,8 +340,13 @@ None of the other fields are considered significant by this library. | ||
#### comment | ||
#### fileComment | ||
`String` decoded with the the charset indicated by `generalPurposeBitFlag & 0x800` | ||
as with the `fileName`. | ||
`String` decoded with the charset indicated by `generalPurposeBitFlag & 0x800` as with the `fileName`. | ||
(The Info-ZIP Unicode Path Extra Field has no effect on the charset used for this field.) | ||
If `decodeStrings` is `false` (see `open()`), this field is the undecoded `Buffer` instead of a decoded `String`. | ||
Prior to yauzl version 2.7.0, this field was erroneously documented as `comment` instead of `fileComment`. | ||
For compatibility with any code that uses the field name `comment`, | ||
yauzl creates an alias field named `comment` which is identical to `fileComment`. | ||
#### getLastModDate() | ||
@@ -470,2 +507,5 @@ | ||
* 2.7.0 | ||
* Added option `decodeStrings`. [issue #42](https://github.com/thejoshwolfe/yauzl/issues/42) | ||
* Fixed documentation for `entry.fileComment` and added compatibility alias. [issue #47](https://github.com/thejoshwolfe/yauzl/issues/47) | ||
* 2.6.0 | ||
@@ -472,0 +512,0 @@ * Support Info-ZIP Unicode Path Extra Field, used by WinRAR for Chinese file names. [issue #33](https://github.com/thejoshwolfe/yauzl/issues/33) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
53052
646
530